【问题标题】:How to combine MVC4 with EF5 Db First separate project如何将 MVC4 与 EF5 Db First 单独项目结合起来
【发布时间】:2013-04-06 20:57:35
【问题描述】:

在我的解决方案中,我有两个项目。一个是主要的 MVC4 项目。另一个是 DataLayer 项目,其中包含从现有数据库(可能稍后还有一些存储库)生成的 Entity Framework 5 edmx 模型。

问题是 pocos EF5 生成位于 DataLayer 项目中。但我需要它们在 MVC4 项目的 Models 文件夹中。

我希望单独的 DataLayer 项目增加关注点的抽象和分离,但我不知道如何将这两个部分放在一起。
(我想在 Models 文件夹中再维护一层 pocos,但这似乎不对)

【问题讨论】:

  • 为什么在 MVC4 项目中“需要”它们? EF 将在创建 .edmx 的同一程序集中生成这些类。如果您需要访问这些模型,请记住从 MVC4 项目中添加对您的数据项目的引用。然后你可以引用模型 Data.EntityObjectName (或者你的命名空间工作)
  • @Tommy 是的,但是这些类不位于 Models 文件夹中。一个缺点是 Visual Studio 无法在“添加视图”对话框中将它们识别为可供选择的模型。也许还有其他缺点。 Models 文件夹是 MVC4 模板尝试创建的顺序中的关键部分。我觉得把它留空是不对的。
  • @YaronLevi 在以这种方式生成视图时,我通常将该模型字段留空。滚动需要很长时间,而且我已经知道我想要的模型的完整命名空间。所以我只是在视图顶部手动声明它。 @model FullNamespace.ViewModel
  • 是的,它们确实会显示在该下拉列表中,您只需要在添加或删除对数据项目模型的任何更改之前重新编译数据项目。
  • 如果您将 EF 模型视为域模型,我认为下一步对您来说会更清楚。让 EF 在你的域项目中做这件事,然后让你的 mvc4 项目的 repos 构建一些客户端友好的模型。这允许您有一个单独的模型来装饰视图等,并允许您将域模型分开。请参阅下面的答案。

标签: c# asp.net-mvc-4 entity-framework-5 ef-database-first


【解决方案1】:

按照您的描述,我将我的项目分为两个。

我想在 Models 文件夹中再维护一层 pocos,但这似乎不对

我想你会发现你最终会构建这一层。

这里有两个项目 Project.DataProject.Web。 Project.Web 有一个对 Project.Data 的项目引用。

  • Project.Data.Models:实体
  • Project.Web.Models:DTO、ViewModels

我的观点从不直接引用实体。我将使用 AutoMapper 将实体映射到 DTO 或 ViewModel。这发生在我的 services 中,它位于自己的命名空间下的 Project.Web 中。我的服务从不返回实体类型,我的视图只使用 ViewModel。

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;
    }
}

控制器动作:

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

编辑: 添加了另一个模型层来映射实体 => DTO => 查看模型

【讨论】:

  • 虽然您不应该从数据层返回视图模型,但它仍然有效。您应该返回 EF5 生成的模型或更好的 DTO 对象,然后将其映射到控制器中的视图模型
  • @Ryan 我没有从数据层返回视图模型。在这个例子中,服务不是我的数据层,而是封装了我的业务逻辑。这里 EF 是数据层。
  • 对不起,我不应该说数据层,但无论如何视图模型都应该只在控制器级别创建。想想看。如果 FooService 由 iOS 客户端调用,则视图模型可能完全不同。
  • @Ryan 我认为鉴于这种架构的简单性,我的服务返回 DTO 或“ViewModels”是值得商榷的。你提倡每个视图一个视图模型吗?
  • 你可能是对的,但我认为为什么不努力:P
【解决方案2】:

这是存储库的工作。创建 DTO 类来保存视图友好的模型,并使用存储库来调用您的数据层并组装 dto。然后可以专门构建 dto 以返回给客户端,包括任何序列化或显示装饰等。这里没有什么复杂的。

我认为有些人的第一反应是“如果我必须创建这些类,我就是在重复我的努力”,但你真的不是,因为这些类服务于不同的目的,这正是你所说的,关注点分离.

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;}
}

我在这里展示两个不同的 EF 引用(您的数据库实体架构)的唯一原因是为了说明这将是您在返回 FINISHED dto 以供使用之前进行任何“附加”处理的机会。

【讨论】:

  • 所以按照您的解释,存储库创建的 DTO 是位于 MVC4 项目的 Models 文件夹中的“Models”?
  • 是的。一般来说,我的模型文件夹至少有 2 个子文件夹,dtos 和 viewmodels。我的视图模型是我绑定到视图的,它们包含任何需要的 dto。这也应该尊重 SOLID 设计中的 S。也就是说,视图模型的职责是以它需要的格式向视图提供它需要的数据
猜你喜欢
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多