2

Models for the database (using EF6) have certain attributes like Key, NotMapped, or Required (which will set the column in SQL Server to not null) while models which interact with the MVC portion of the website have their own attributes. An example of that is also Required which I use for data validation when a user is submitting a form and which will do fancy things like show error messages on the web page (when I check Model.IsValid).

My question is if these two "groups" of method attributes are compatible or should I have one set of models that I use for interaction with EF and another set of models that are used to move data between the Logic/DataAccess layers and the Controller. The idea would be to use something like AutoMapper between the two sets of models.

When necessary, of course, I'll create ViewModels and map whatever I need to those.

  • 1
    They are compatible, so you can apply everything that matters on the EF properties. However, there are certain cases where you need an encapsulating object as well. – Berin Loritsch Apr 28 '17 at 17:16
  • @BerinLoritsch What do you mean by "encapsulating object"? Is that something that would hide the attributes and mess up front end validation? – birdus Apr 28 '17 at 17:26
  • An example is an index page where you have a list of items. You'll also need additional properties to control whether you allow a "next page", "previous page" and show "page X of Y" data. – Berin Loritsch Apr 28 '17 at 18:21
5

Attribute constraints are the least of your problems. EF models are not POCO objects, they are DTO entities which are very tightly inter-twined with your database schema and your DbContext/DbSets.

There's a huge amount of invisible logic lurking behind those innocent looking get and set properties; they (the DTO entities) do all kinds of magical 'EF' things, such as:

  • Translate your LINQ-to-Entities queries into SQL
  • Handle lazy loading
  • EF models are also tied into the EntityState for the DbContext

Unfortunately, a lot of getting-started ASP.NET MVC tutorials have you putting those models into your controllers. Those tutorials are teaching you a really bad habit which will bite you hard as soon as you try to do something non-trivial

For example, imagine you have an Employee EF model, which also has a method in it called GetManager().

See this bit of LINQ, looks innocent right?

var managers = from emp in MyDbContext.Employees
               where emp.Department == "Sales"
               select emp.GetManager();

if MyDbContext.Employees were something simple like a List<Employee> where Employee is a regular POCO, this would be fine. but unfortunately the above query will throw an exception because it tries to convert emp.GetManager() into a SQL statement - except there is no such thing as GetManager in SQL...

Another issue - if you have any lazy-loaded properties which you attempt to use after DbContext.Dispose(), you'll find yourself either needing to forcibly load the property before you dispose (and remember to set EntityState.Detached too), or performing all of your business logic within your using block.

Of course, that might be ok if you have very simple business logic which only cares about a few simple database entities; you need to keep perspective and remember that KISS is also important.

However, its reasonable to expect you might also need to grab some data from another source, like a file, a network service, another API or other database, etc. Business logic which happens inside an EF using block is a common pathway to technical debt and hard-to-maintain code.

Of course, all of these are things which you can 'work around', but the result is likely to mean mixing all of your UI logic in with your business and data layer logic; separation of UI concerns versus Database concerns becomes awkward when you use EF models in a Controller.

So, be very careful when deciding to use EF models directly in your MVC Controllers because anything marginally non-trivial can see you fighting all kinds of exceptions thrown by EF which you wouldn't see in regular mapped POCO models. The price to pay for the nominal amount of extra boilerplate code which maps from your EF models to your 'Business Layer' models is very reasonable, compared with the awful technical debt which you can end up with otherwise.

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.