简体   繁体   中英

How to combine MVC4 with EF5 Db First separate project

In my solution I have two projects. One is the main MVC4 project . The other is a DataLayer project which contains an Entity Framework 5 edmx model generated from an existing DB (and maybe some Repositories later).

The problem is that the pocos EF5 generates sits in the DataLayer project. But I need them inside the Models folder in the MVC4 project.

I want the seperate DataLayer project to increase abstraction and separation of concerns, but I can't figure out how to put those two pieces together.
(I thought to maintain another layer of pocos in the Models folder but this dose not seems right)

I have my projects separated into two as you describe.

I thought to maintain another layer of pocos in the Models folder but this dose not seems right

I think you will find you will build this layer eventually.

Here's two projects Project.Data and Project.Web . Project.Web has a project reference to Project.Data.

  • Project.Data.Models: Entities
  • Project.Web.Models: DTOs, ViewModels

My views never directly reference Entities. I will map Entities to DTOs or ViewModels using AutoMapper. This happens in my services which sits in Project.Web under its own namespace. My services never return Entity types and my views use only ViewModels.

interface IFooService
{
    FooDTO GetFoo(int id);
}

public class FooService : IFooService
{
    public FooDTO GetFoo(int id)
    {
        var foo = dbContext.Foo.Where(f => f.Id == id).Select(f => new FooDTO {
            Bar = f.Bar,
            Blah = f.Blah
        }).FirstOrDefault();
        // I let AutoMapper take care of the mapping for me
        var foo = Mapper.Map<FooDTO>(dbContext.Foo.Where(f => f.Id == id).FirstOrDefault());

        return foo;
    }
}

Controller Action:

public ActionResult FooDetails(int id)
{
    FooViewModel foo = Mapper.Map<FooViewModel>(fooService.GetFoo(id));
    return View(foo);
}

Edit: Added anther model layer to map Entity => DTO => View Model

This is the job of the repository. Create DTO classes to hold view friendly models and use the repository to call your data layer and assemble the dto. The dtos can then be built specifically for being returned to the client, including any serialization or display decorations, etc. Nothing complicated here.

I think some people's first reaction is "I'm duplicating my effort if I have to create these classes" but you're really not as these classes serve a different purpose which is exactly what you're saying, separation of concerns.

public MyViewModel // model that is bound to the view
{
    private UserRepository _userRepo;
    public EmployeeDto ActiveUser {get;set;}

    public MyViewModel()
    {
        _userRepo = new UserRepository();
        LoadActiveUser();
    }

    private void LoadActiveUser()
    {
        var userId = (int)HttpContext.Current.Session["activeUser"] ?? 0;
        if(userId > 0)
        {
            ActiveUser = _userRepo.GetEmployee(userId);
        }
    }

}

public UserRepository
{
    private SomeEntityReference1 _myDal1;
    private SomeEntityReference2 _myDal2; // maybe you need to make some other data layer call in order to fill this object out

    public UserRepository()
    {
        _myDal1 = new SomeEntityReference1 ();
        _myDal2 = new SomeEntityReference2 (); 
    }

    public EmployeeDto GetEmployee(int id)
    {
        var empDto = new EmployeeDto();
        // get employee
        var dalEmpResult = _myDal.Employees.FirstOrDefault(e => e.EmployeeId == id);
        empDto.FirstName = dalResult.FName;
        empDto.LastName = dalResult.LName;
        empDto.Id = dalResult.EmployeeId;

        // get employee department info
        var dalDeptResult = _myDal2.Departments.FirstOrDefault(d => e.DepartmentId == dalEmpResult.DeptartmentId);
        empDto.DepartmentName = dalDeptResult.Name;

        return empDto;
    }
}

// client friendly employee object
[DataContract(Name="Employee")]
public class EmployeeDto
{
    public int Id {get; internal set;}

    [DataMember(Name="fname")]
    [DisplayName("Employee First Name:")]
    public string FirstName {get;set;}

    [DataMember(Name="lname")]
    [DisplayName("Employee Last Name:")]
    public string LastName {get;set;}   

    public int DeptId {get;set;}

    [DataMember(Name="dept")]
    [DisplayName("Works at:")]
    public string DepartmentName {get;set;}
}

The only reason I show two different EF references here (your database entity schemas) is just to illustrate that this would be your opportunity to do any "additional" processing before returning a FINISHED dto, ready for consumption.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM