3

Let's say I'm starting a Web Application project that uses a) ASP.NET MVC b) Entity Framework

In terms of Software ARchitecture, correct me if I'm wrong,

-1) Could I place all my Entity Framework code in a Data Access Layer folder ( DAL )?

Furthermore,

-2) Would it be correct to say that the Entity Framework code which is within the Data Access Layer Folder (DAL) is part of the Model in the ASP.NET MVC from a software architecture perspective?

  • 1
    Yes, it's part of the model. Whether you put it in a Data Access folder is entirely up to you. – Robert Harvey Sep 22 '15 at 15:55
  • Thx. However, isn't EF definitely always part of the Data Access Layer since EF is an ORM that is the middle-man between the OO world and the Database world? – user1338998 Sep 23 '15 at 2:03
  • It's just terminology. But yes, EF is generally regarded as part of the Data Access Layer. – Robert Harvey Sep 23 '15 at 2:08
3

In a simple application you can use a single class as EF entity, domain model, and view model.

In more complex applications all these models became different classes. For example, code first entities and ASP.NET MVC models have different annotations (KeyAttribute in EF, DisplayFormatAttribute in MVC), and usually you shouldn't mix them in a single class.

Also, all EF properties should be writeable, but domain properties can be read-only. MVC models can contain specific SelectList, but domain models and entities shouldn't.

So in complex application you have separated models at each application's tier (presentation, domain, data-access), and you should map these models at tier's boundaries.

Lets look the small example of a blog. Each post in a blog has creation date/time and (imaging) a category:

EF

[TableName("PostCategories")]
public class EfCategory
{
    public int CategoryId { get; set; }

    public string Name { get; set; }
}

public class EfPost
{
    public DateTime Created { get; set; }

    public virtual Category Category { get; set; }

    public int CategoryId { get; set; }

    . . .
}

You see, Post.Created is writeable and readable property, and Category has TableName attribute. Can you use these classes in the domain tier?

No. First, the creating date/time property is read-only in the domain, you can't change it. Second, what if you'll want rewrite data-access with NHibernate or ADO.NET? You'll can't cause your domain model Category has the attribute TableName.

So, you can create duplicate domain models:

Domain

public class DomainCategory
{
    public int Id { get; private set; }

    public string Name { get; private set; }

    public DomainCategory(int id, string name)
    {
        Id = id;
        Name = name;
    }
}

. . .

public EfCategoryRepository : ICategoryRepository
{
    private readonly DbContextFactory dbContextFactory;

    . . .

    public CategoryRepository(DbContextFactory dbContextFactory)
    {
        this.dbContextFactory = dbContextFactory;
    }

    . . .

    public DomainCategory GetById(int id)
    {
        using (var dbContext = dbContextFactory.CreateReadOnlyContext())
        {
            var entity = dbContext.Set<EfCategory>.Single(c => c.Id == id);

            return new DomainCategory(entity.CategoryId, entity.Name);
        }
    }
}

Now the domain's interface ICategoryRepository that "knows" about domain models, is implemented by EF data access class EfCategoryRepository. This implementation "knows" about EF models and can map EF to domain.

Domain (continue)

public class DomainPost
{
    public DomainCategory { get; set; }

    public DateTime Created { get; private set; }

    . . .

    public DomainPost(EfCategory category, DateTime created, ...)
    {
        Category = new DomainCategory(category.CategoryId, category.Name);
        Created = created;
        . . .
    }
}

Domain's property Created is read-only dislike the EF's property.

Finally, if we think about view (ASP.NET MVC) edit model, we'll find that this model should contain the list of categories and shouldn't contain Created cause user can't change it:

Presentation

public MvcEditPost
{
    public int Id { get; set; }

    [Display("Category")]
    public int CategoryId { get; set; }

    public IEnumerable<SelectListItem> Categories { get; set; }
}

public ActionResult Edit(int id)
{
    var domainPost = postRepository.GetById(id);
    var modelPost = new MvcEditPost
    {
        Id = domainPost.Id,
        CategoryId = domainPost.Category.Id,
        Categories = categoryRepository.GetAll()
                                       .Select(c => new SelectListItem
                                       {
                                           Selected = c.Id == domainPost.Category.Id,
                                           Text = c.Name,
                                           Value = c.Id.ToString(),
                                       }),
    };

    return View(modelPost);
}

@model MvsEditPost
@using (Html.BeginForm("Post", "Edit", { Id = Model.Id }))
{
    @Html.DropDownListFor(m => m.CategoryId, Model.Categories)
}

So, the presentation code is also "knows" about both presentation and domain models and can map firsts to seconds. This model differentiation let you make all tiers independent. More precisely, a presentation tier and a data-access tier are depending on a domain tier now. So you can simple rewrite data-access (SQL Server to Oracle, EF to NHibernate, Single data-server to cloud), or you can simple rewrite presentation (MVC to Desktop, MVC to Console). You wouldn't be able to do it without models' differentiation.

  • This is good advice, but it's written from the perspective of someone who's worked with ASP.NET MVC for awhile. Newcomers to ASP.NET MVC will probably not understand it. – Robert Harvey Sep 22 '15 at 15:55
  • If you don't create a domain model, just because you don't want to do the mapping, I'd suggest using AutoMapper. This way, the mapping overhead is very small. – Etsitpab Nioliv Apr 14 '17 at 14:57
0

I guess you are talking about a single asp .net MVC website?

I think the intention of Microsoft is the EF is the M in MVC, your entities are you models, you map them into views and persist them to a db which is automagically created for you.

However. This tends to fall down on larger projects. Conceptually EF is part of the data access layer, in the same way as SqlConnections and DataReaders etc. Ideally you should put wrap it in a repository of some kind, make sure it only calls Stored Procedures and hide it away from your domain models.

Of course if you do this a lot of the time saving features of EF are made redundant. so you have to make a call about where to draw the line.

  • If you're only going to call stored procedures, don't you lose some of the benefits of EF? – JeffO Sep 22 '15 at 17:23
  • @JeffO I have found even wrapping EF in a repository layer you loose some of the benefits. It is wrapping a repository and unit of work in another repository and unit of work. – RubberChickenLeader Sep 22 '15 at 20:40
  • I guess it depends on what you consider to be benefits. SProcs are the classic solution to abstraction of db optimisations from code, just look at the number of stack over flow questions along the lines of 'my EF query is slow, what do I do?!' but as I say you have to weigh 'writing boilerplate code' vs 'architectural correctness' – Ewan Sep 22 '15 at 21:00
  • @Ewan I agree that EF can be the wrong tool in certain situations, but SP's do limit the ability to query accross 15 different related entities with linq and lamda's which is where I find the usefullness of EF (speed of development with a known tradeoff of acceptable performance loss). The complex stuff is in SP's for performance. – RubberChickenLeader Sep 22 '15 at 21:23
  • No, EF is not the M in any of the MVx patterns. As soon as you try to map you business objects (your models) directly with an ORM, you're forcex to change the public API of model just for the sake of the database, which twists your models using the wrong concerns. You should be able to swap out EF without changing the public API of your BOs. – Andy Sep 22 '15 at 21:55
0

Entities are the model, (EF) queries are data access.

I personally use the 3-tier system where the GUI (presentation layer) is as dumb as possible, asking everything be done by services (BLL/business logic layer) which uses the DAL (data access layer) to persist data (whether is be SQL or files or any other data access you can think of):

+-----+----+
| GUI |    |
+-----+ En |
| BLL | ti |
+-----+ ti |
| DAL | es |
+-----+----+

In a simple design your entities will be passed back and forth by all these layers. For more complex designs (which are more flexible, yet take more typing) the GUI will use ViewModels, the BLL functions accept and return Business Entities and the DAL takes and returns simple POCO's.

You can test your design by trying to swap out and replace your EF-based DAL with an Oracle-based one and you should be able to do so without touching your BLL or GUI. In the same fashion you should be able to take your GUI and replace it with a command-line application that enables you to perform all the same operations without you having to write lot more than simple calls to the BLL.

Also, in a service-oriented architecture, the entities should not contain any logic, as opposed to for a domain-driven design.

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.