Question

In this blog post titled "Pragmatic Linq", Marc Gravell discusses how to implement the repository pattern in a way that allows Linq-to-entities to be used in the data access layer (DAL), without allowing that implementation detail to leak beyond the DAL, and without making it difficult to properly test the DAL.

One of the issues Mark raises is that the DAL classes will typically contain navigation properties, which in most cases should not be part of the public API:

Navigation properties ... very quickly start crossing aggregates and/or causing lazy behaviour (not good if your context no longer exists)

Traditionally, this might be tackled by creating one set of classes (complete with EF navigation properties) for use in the DAL, and another set of classes (without the navigation properties) to be used in the public API of the DAL. However, Mark does not favour that approach:

I don't really want to declare and maintain a "pure" (i.e. separate to the DAL) object model

He suggests instead that it might be possible to use a single set of classes, yet keep the navigation properties internal to the repository:

My current thinking with this is that ... most navigation properties should be marked as internal to the data layer. This means that your repository implementation can use the navigation properties to construct interesting queries, but the public API surfaced back to the caller doesn't include them. If the caller gets and order from the order repository, and wants details about the customer: tough - go and ask the customer repository.

That sounds good to me - in fact, I have just spent several hours trying to refactor my DAL in this way. However, having got to the point where everything compiles and I can start running/testing it, I've discovered a problem.

I'm using Entity Framework code-first (EF6, if it matters) to persist the entities, and I've marked as internal any properties in my entity classes that I don't want to be part of the public API of my DAL. (I've moved my data-access code into a separate assembly, so that internal actually means something).

However, it turns out that any property marked as internal is ignored by Entity Framework! For example, I have an integer FooId property that I use internally, and which I don't want to expose, so I marked it as internal. And now, if I allow EF to re-create my database, it does not create a FooId column on the relevant table.

Worse, with the navigation properties marked as internal, it now no longer creates a foreign-key relationship between the corresponding tables. I imagine that it will no longer support lazy-loading of those navigation properties either, though I've not tested that.

Did I misunderstand what Marc was proposing? Is there another way to keep some properties internal to the DAL, yet be fully supported by EF?

Could I, for example, create a base class for use in the API that has only the public properties, and then have a derived class with the extra properties that's used internally (and with EF)? That sounds like it might work, but then I'd have a naming clash (I'd want my API to use classes with a meaningful name like "Customer", but I'd also want my internal class to be called "Customer" so that EF would create sensibly-named database tables. I guess I could force the table name by overriding the convention, but still...).

Was it helpful?

Solution

By default Code First will just include public properties in your model. But you can use the FluentAPI to map internal properties. You can even map private properties that way (if you look at the references for the extra steps required in that case).

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    {
        modelBuilder.Entity<User>().HasMany(x => x.Projects);
    }

References:

http://blog.oneunicorn.com/2012/03/26/code-first-data-annotations-on-non-public-properties/

http://romiller.com/2013/01/23/ef6-code-first-mapping-all-private-properties-using-custom-conventions/

BTW by convention FooID would be a foreign key for a navigation property named Foo

OTHER TIPS

It isn't so much as EF ignores navigation properties, but it can't reflect over them without privilege. Adding that would add a requirement of running EF in trusted mode, which is another can of worms. There are two ways I can think of to solve this, neither of which I have tested by the way.

Weaving your properties at compile time.

With this approach, you compile your internal properties to public properties in your dll. This way EF can reflect over the properties. However, since your source still uses internal you know your business layer won't have source that references these properties.

The downside of this approach is that it doesn't work when you reference by dll, rather than by project.

You can implement this with a number of technologies, such as Fody/Publicize, or PostSharp.

Explicitly mapping your properties in an EntityMapper<> class

As the name suggests, you explicitly map your properties, so that EF does not need to reflect over your class to be able to find out about the properties.

In theory, EF should be able to use an Expressions.PropertyExpression to do all the set/get operations it needs. As well as override the properties in question for the proxy classes. In practice, I am not so sure.

I think you misunderstood what navigation property means. See http://msdn.microsoft.com/en-us/library/vstudio/bb387104%28v=vs.100%29.aspx

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top