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...).