Confusion about where to put business logic when using Entity infrastructure

I just started working with the Entity framework, and I'm confused about how the classes that usually go into the business layer fit into the objects created by the Entity Framework.

When working with classic ADO.NET, I would have a class called Customer, and then another class called DALCustomer to handle interacting with databases. In this structure, I would put the code to perform calculations, filter and process the DAL instance with the client for saving, updating and deleting in the Customer class.

Using the Entity Framework, if you have a Customer table, the Entity framework creates an object called Customer, and this is where my confusion begins, does that object remove the need for a client at the business level? So, essentially all the fields and methods that usually go into the business layer go into the entity generated by the Entity Framework? Or, if the class still exists in the CustomerBL business layer, for example, which still contains the fields and methods needed to execute the business logic needed for computing, filtering, and still needs an EF DAL instance declared to handle data access ?

If there should be a business class, in this case CustomerBL, another question arises if the fields created in the customer object will be recreated in CustomerBL or an instance of the Customer object must be declared in CustomerBL, so there would be no need to declare the fields in two places ?

+45
c # entity-framework
Jan 15 '13 at 17:56
source share
5 answers

The Entity structure, in contrast to linq-to-sql, for example, was developed taking into account the separation of the data model and the conceptual model. It supports inheritance , object splitting, table splitting , complex types and transparent many-to-many associations , all of which allow you to format the domain model to meet your needs without limiting the data warehouse model too much.

The first code approach allows you to work with POCO, in which the selected properties can be mapped to columns of the data warehouse. First, Model-first and Database-first generate partial classes, allowing you to extend the generated code. Working with these classes is largely related to the work of POCOs. Even more since version 5, when DbContext became the standard API, so the generated classes were no longer DbContext with persistence-related code in the ObjectContext API.

Of course, this separation of the conceptual model and the store model can only be achieved to a certain extent. Some things work against this goal of maintaining ignorance. For example, if lazy loading is required, you need to declare the navigation properties as virtual , so EF can override them in proxy types. And it’s very convenient to have primitive properties of a foreign key (for example, ParentId ) that accompany the “real” associations (a Parent reference). Purists consider this a violation of domain-driven rules.

Another important violation of persistence in ignorance is the large number of differences between linq-to-objects and linq-to-entity . You simply cannot ignore the fact that you are connected with a completely different universe than with objects in memory. This is called a tight connection or fuzzy abstraction .

But then ... in general, I am pleased to use the generated EF or POCOs classes from the first code model as domain classes. So far, I have never seen a transition to friction from one data warehouse to another, if at all. Maintaining ignorance is fiction. DAL features always leave a mark on the field. Only when you need to code different data warehouses / models or when stores / models are expected to change relatively often, does it pay off in order to minimize this footprint or completely abstract it.

Another factor that can contribute to EF classes in domain classes is that many applications today have several levels where (serialized) different view models or DTOs are sent to the client. Using domain classes in user interfaces is hardly ever suitable for an account. You can also use EF classes as a domain and provide services to highlight dedicated models and DTOs, as required by the user interface or service users. Another layer of abstraction may be more of a burden than a blessing, if only in terms of productivity.

+24
Jan 15 '13 at 20:05
source share

In my opinion, the whole point of using POCOs as objects that can be saved is to eliminate the distinction between “database entities” and “business entities”. "Entities" must be "business entities" that can directly be stored and loaded from the data warehouse and, therefore, simultaneously act as "database entities." Using POCOs, business objects are separated from a specific mechanism for interacting with the database.

You can move objects to a separate project - for example - that does not have references to any EF assembly and still uses them in a database-level project to manage storage.

This does not mean that you can completely design your business objects without having the requirements for EF. There are limitations that you need to know to avoid problems when you come to the point to map business objects to a database using EF, for example:

  • You must make the navigation properties (links or collections of links to other objects) virtual to support lazy loading using EF
  • You cannot use IEnumerable<T> for collections that need to be saved. It must be ICollection<T> or more derived.
  • It's not easy to keep private properties
  • The char type is not supported by EF, and you cannot use it if you want to store its values.
  • and much more...

But an additional set of objects - in my opinion - an additional level of complexity, which should be justified in order to be really necessary if these restrictions are too stringent for your project.

YA2C (2 more cents :))

+13
Jan 15 '13 at 20:16
source share

I don’t know if he considered good practice to be different, but personally this is how I dealt with it in the past:

The classes created by EF are your DAL, and then for BL they create an additional set of classes in which you will have the required structure (for example, it is possible to combine data from related objects in a one-to-one relationship) and other business logic (user verification, for example implementation of IDataErrorInfo so that it plays well with the user interface in WPF, for example), and also create classes that will contain all business-level methods related to the type of entity that use BL instances and convert from from EF objects to about ektov BL.

So, for example, you have a Client in your db. EF will generate the Customer class, and in BL there will be the Customer class (prefix, suffix, etc.) And the CustomerLogic class. In the BL Customer class, you can do whatever is necessary to satisfy the requirements, without having to intervene in EF objects, and in the CustomerLogic class you would have BL methods (loading the most respected customers, saving customers with additional data, etc.).

Now this will allow you to be loosely related to the implementation of the data source. Another example of why this helped me in the past (in a WPF project) is that you can do things like implement IDataErrorInfo and implement validation logic in CustomerBL classes so that when you bind an object to a create / edit form in a custom In the interface, you will benefit from the built-in functions provided by WPF.

... My 2 cents, I am also interested to know what is the best practice or what other solutions / points of view.




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

+5
Jan 15 '13 at 18:06
source share

This question may be a little old, but it may help. Andras Nemes noted in his blog his preoccupation with the use of DDD (Domain Design) over technology 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/

+2
Mar 28 '14 at 13:11
source share

I used business logic to write my methods and return the results in the created form, for example:

 namespace Template.BusinessLogic { public interface IApplicantBusiness { List<Template.Model.ApplicantView> GetAllApplicants(); void InsertApplicant(Template.Model.ApplicantView applicant); } } 
0
Jul 22 '14 at 21:19
source share



All Articles