57

I've just started working with the Entity framework and I'm confused about how the classes normally in the business layer fit in with the entities that are created by the Entity Framework.

When working with classic ADO.NET, I would have a class called Customer for example and then another class called DALCustomer to handle database interaction, in this structure I would have put the code to do calculations, filtering and delcare an instance of the DAL withing Customer for saving, updating and deleting in the Customer class.

With the Entity Framework, if you have a table called Customer, the Entity framework creates an entity called Customer and this is where my confusion begins, does this entity remove the need for a Customer in the business layer? So in essence all the fields and methods that normally go in the business layer go in the entity generated by the Entity Framework? Or should a class still exist in the business layer called CustomerBL for example, that still contains the fields and methods needed to accomplish the business logic required for calculations, filtering and still needs an instance of the EF DAL declared to handle data access?

If there should be a business class, in this case CustomerBL, one other question jumps to mind, should the fields that are created in the customer entity be recreated in CustomerBL or should an instance of the Customer entity be declared in CustomerBL so there would be no need to have the fields declared in 2 locations?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
obb-taurus
  • 847
  • 1
  • 7
  • 12

5 Answers5

28

Entity framework was designed with separation between data model and conceptual model in mind. It supports inheritance, entity splitting (not EF core), table splitting, complex types or owned types, and transparent many-to-many associations (not EF core), all of which allow molding the domain model to one's needs without being constrained too much by the data store model. EF core supports shadow properties which can be used to hide cross-cutting concerns from the exposed class model.

The code-first approach allows working with POCOs in which only a few properties are mapped to data store columns and others serve domain goals. Model-first and Database-first generate partial classes, allowing one to extend the generated code.

Of course this separation of conceptual model and store model can only succeed to a certain extent. Some things work against this goal of persistence ignorance. For instance -

  • If lazy loading is desirable, it is necessary to declare navigation properties as virtual, so EF can override them in proxy types. Domain-driven design (DDD) would encourage using virtual only when polymorphism is required.

  • It is very convenient to have primitive foreign key properties (say, ParentId) accompanying the "real" associations (a Parent reference). Purists consider this a violation of DDD principles.

  • The EF class model will is part of a data access layer and should primarily serve that goal. Therefore, it will contain many reciprocal relationships, in order to benefit from navigation properties as much as possible when writing LINQ queries. These mutual relationships are another violation of DDD principles.

  • There is a large number of differences between LINQ-to-objects and LINQ-to-entities. You just can't ignore the fact that you are LINQ-ing against a totally different universe than objects in memory. This is referred to as tight coupling, or leaky abstraction.

  • EF can only map concrete classes, no interfaces.

But then... generally I'm happy with using generated EF classes or POCOs from a code-first model as domain classes. So far, I've never seen a frictionless transition from one data store or ORM to another, if it happens at all. Persistence ignorance is a fiction. Idiosyncrasies from the DAL easily leave a footprint in the domain. Only when you have to code for different data stores/models or when stores/models are expected to change relatively often it pays off to minimize this footprint as much as possible or abstract it away completely.

Another factor that may promote EF classes as domain classes is that many applications today have multiple tiers, where (serialized) different view models or DTOs are sent to a client. Using domain classes in UIs hardly ever fits the bill. You may as well use the EF class model as the domain and have services return dedicated models and DTOs as required by a UI or service consumers. Another abstraction layer may be more of a burden than a blessing, if only performance-wise.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • I don't understand what you mean by `resists the temptation to rely on things EF puts in there, like INotifyPropertyChanged`? The t4 templates can be modified to implement things like this if needed. –  Jan 15 '13 at 20:51
  • Sure, they can be modified. I mean that using these EF generated properties and methods breaks persistence ignorance even more. And the standard templates may change with new versions. – Gert Arnold Jan 15 '13 at 20:53
  • 6
    Gert, no disrespect intended but could you join me down at my level and perhaps give me an idea how what you are saying applies to the example in my original post as I'm not completely following you because after all I am very new to the EF. – obb-taurus Jan 15 '13 at 21:01
  • 3
    That's OK boss! It all boils down to one advice (my opinion): use the EF classes as-is. Which is the `Customer` class and not an extra `CustomerBL` class. Use partial classes to extend the generated classes with business logic. – Gert Arnold Jan 15 '13 at 21:10
  • So, if I'm understanding you correctly, forgoing the traditional physical seperations of UI, BL and DAL and in essence merging BL and DAL into one utilizing partial classes, is that in essence the gist of it? – obb-taurus Jan 15 '13 at 21:50
  • Yes, I think Slauma expressed this well by saying '"business entities" (...) act as "database entities" at the same time'. – Gert Arnold Jan 15 '13 at 21:59
16

In my opinion the whole point of using POCOs as entities that can be persisted is to remove the distinction between "database entities" and "business entities". "Entities" are supposed to be "business entities" that directly can be persisted to and loaded from a data store and therefore act as "database entities" at the same time. By using POCOs the business entities are decoupled from the specific mechanism to interact with a database.

You can move the entities into a separate project - for example - that has no references to any EF assembly and yet use them in a database layer project to manage persistence.

This does not mean that you can design your business entities completely without having the requirements for EF in mind. There are limitations you need to know to avoid trouble when you come to the point to map the business entities to a database schema using EF, for instance:

  • You must make navigation properties (references or collections of references to other entities) virtual to support lazy loading with EF
  • You cannot use IEnumerable<T> for collections that have to be persisted. It must be ICollection<T> or a more derived type.
  • It's not easy to persist private properties
  • The type char is not supported by EF and you can't use it if you want to persist its values
  • and more...

But an additional set of entities is - in my opinion - an additional layer of complexity that should be justified to be really needed if the mentioned limitations are too tight for your project.

YA2C (Yet another 2 cents :))

Slauma
  • 175,098
  • 59
  • 401
  • 420
  • 3
    I agree with this as well it is the underlying mechanisms of the ORM which 'replace' the data layer and not the entities themselves. In a MVC type application I may create separate ViewModels to express specific information not derived from the Entity as required. Just like the OP though I still find this difficult to navigate at times. – Matthew Jan 15 '13 at 20:39
6

I don't know if it's considered a good practice by others but personally this is how i handled this in the past:

The classes generated by EF are your DAL, and then for BL create a complementary set of classes in which you will have the structure you require (like maybe merging data from related entities in a one to one relationship) and other business logic concerns are handled (custom validation like implementing IDataErrorInfo to make it play nice with the UI in WPF for instance) and also create classes that would contain all the business layer methods relating to a type of entity, that use the BL instances and convert to and from EF entities to the BL objects.

So, for instance, you have Customer in your db. EF will generate a class Customer, and in the BL there will be a Customer (prefix, suffix, etc.) class and a CustomerLogic class. In the BL Customer class you can do whatever is needed to satisfy requirements without having to tamper with the EF entities and in the CustomerLogic class you would have BL methods (load most valued customers, save customer with extra data, etc.).

Now, this enables you to be loosely coupled to the datasource implementation. Another example of why this has benefited me in the past (in a WPF project) is that you can do stuff like implement IDataErrorInfo and implement validation logic in the CustomerBL classes so that when you bind the entity to a create/edit form on the UI you will benefit from the built in functionality provided by WPF.

...My 2 cents, i am also curious to find out what is the best practice or what other solutions/points of view are.


Also perhaps related to this topic - Code-first vs Model/Database-first

Community
  • 1
  • 1
dutzu
  • 3,883
  • 13
  • 19
  • How would you handle the fields that are generated by the EF and are needed in the BL class? Can you provide a bit of a sample of your method? – obb-taurus Jan 15 '13 at 20:31
  • 1
    Well, all that is missing from what i wrote it the fact that you need methods that will copy data to/from BL/DAL entities, and you isolate yourself further from the DAL by implementing a repository pattern so that you don't access the ObjectSets themselves directly, but instead you call the repositories for CRUD operations – dutzu Jan 16 '13 at 05:29
3

This topic maybe a bit old but this may help. Andras Nemes pointed out in his blog the concern of using DDD (domain driven design) over the technology driven design such as EF, MVC, etc.

http://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/

Moe Howard
  • 157
  • 9
masterlopau
  • 563
  • 1
  • 4
  • 13
0

I used the business logic to write my methods and return the results in its created view like:

namespace Template.BusinessLogic
{
    public interface IApplicantBusiness
    {
        List<Template.Model.ApplicantView> GetAllApplicants();

        void InsertApplicant(Template.Model.ApplicantView applicant);
    }
}
Aleksei Zyrianov
  • 2,294
  • 1
  • 24
  • 32