11

In our business logic we occasionally have methods defined something like this:

User.ResetCourse(Course courseToReset)

The problem is that both User and Course are Entity Framework proxy objects. This means that when we hit navigation properties on either User or Course it can cause a huge hit to the database because those objects are not IQueryable so it iterates through them normally.

To solve this we changed the signature to:

User.ResetCourse(MyDBContext db, Course courseToReset)

This means we can directly query the database to make the changes we need in an efficient manner but passing the Database context to a business object just seems so wrong.

We later migrated to user a service layer which means we have something like:

CourseService.ResetForUser(Course courseToReset, User forUser)

This service has a reference to the DBContext injected in on creation but now our business objects are just data bags with no behaviour (i.e an Anemic Domain Model).

How can we avoid this?

  • 11
    Kind of sounds like you've just hit the realisation that entity framework models are actually DTOs, and not really a domain model at all. Are you actually trying to do DDD though? If not, it probably doesn't matter. – Mr Cochese Sep 30 '16 at 14:36
  • 3
    ADM plus services is a good architecture for lots of things – Ewan Oct 1 '16 at 8:23
  • 1
    Pertinent: ADM is not an anti-pattern, it is SOLID design. – John Wu Feb 14 '17 at 19:37
  • 2
    @JohnWu that's a very biased article. Indeed it contains a "Strawman" version of a rich domain model, by including the Active Record pattern in the rich example. Certainly, Active Record is not espoused in DDD and in general is a poor choice for any complex application. – RibaldEddie Apr 17 '17 at 18:18
7

The issue is, you are using EF objects as domain objects in the first place. EF objects are data models NOT business models.

You need to declare business objects which give you the freedom to do as you need, and then retrieve and store them with a repository. Your repository will map the EF entities to your business entities. EF objects should never be used outside of your repositories.

0

You can probably avoid it by doing something like:

CourseService.prepareForUserCourseReset(DBContext db);
User.reset();
Course.reset();
CourseService.completeUserCourseReset(DBContext db);

Or something to that effect, anyway, if you catch my drift. It sounds like the approach that you have with the initial way that you described is performance related, and not necessarily related to the structure of the domain. So really you should consider solving the performance issue in the service layer but can keep the behavior in the domain. It would be helpful to know what it means to reset the User / Course in this context as well if you want a better answer.

-1

Traditionally, this is solved by using a fetching strategy for each use case that instructs Entity Framework to eager load the necessary associations on the initial query using IQueryable.Include().

Udi Dahan wrote a post that describes the general approach, which can be adapted to Entity Framework.

http://udidahan.com/2007/09/16/fetching-strategy-nhibernate-implementation-available/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.