将业务模型转换为视图模型的位置?

问题描述 投票:17回答:3

在我的ASP.NET MVC应用程序中,我正在使用工作单元和存储库模式进行数据访问。

使用工作单元类和在其中定义的存储库,我正在控制器中获取相关的实体集。以我的初学者知识,我可以想到两种获取业务模型并将其转换为视图模型的方法。

  • 存储库将业务模型返回给控制器,此模型比映射到视图模型要大,或者
  • 存储库本身将业务模型转换为视图模型,然后将其返回给控制器。

当前,我正在使用第一种方法,但是对于具有很多属性的视图模型,我的控制器代码开始显得难看且冗长。

另一方面,我在想,因为我的存储库被称为UserRepository(例如),它应该直接返回业务模型,而不是仅对单个视图有用的某些模型。

您认为其中哪一个是大型项目的最佳实践?还有其他方法吗?

c# asp.net-mvc entity-framework repository-pattern unit-of-work
3个回答
21
投票

存储库应返回域模型,而不是视图模型。就模型和视图模型之间的映射而言,我个人使用AutoMapper,所以我有一个单独的映射层,但从控制器调用了该层。

以下是典型的GET控制器操作的外观:

public ActionResult Foo(int id)
{
    // the controller queries the repository to retrieve a domain model
    Bar domainModel = Repository.Get(id);

    // The controller converts the domain model to a view model
    // In this example I use AutoMapper, so the controller actually delegates
    // this mapping to AutoMapper but if you don't have a separate mapping layer
    // you could do the mapping here as well.
    BarViewModel viewModel = Mapper.Map<Bar, BarViewModel>(domainModel);

    // The controller passes a view model to the view
    return View(viewModel);
}

当然可以使用自定义操作过滤器来缩短以避免重复的映射逻辑:

[AutoMap(typeof(Bar), typeof(BarViewModel))]
public ActionResult Foo(int id)
{
    Bar domainModel = Repository.Get(id);
    return View(domainModel);
}

AutoMap定制操作过滤器订阅OnActionExecuted事件,拦截传递给视图结果的模型,调用映射层(在我的情况下为AutoMapper)将其转换为视图模型并将其替换为视图。视图当然是视图模型的强类型。


3
投票

我认为您的存储库应返回业务模型。

然后,您可以使用Automapper之类的工具来自动将属性映射到您的视图模型,并且可以摆脱手动映射代码。如果您不想公开所有业务实体的属性或视图的comples结构,则此方法非常有用。

[您也可能会发现此post有用,在这里您可以摆脱手动映射调用(之类的),并且它还提供了一个很好的示例,说明如何使用视图模型等(在我看来)-或至少获得某种灵感。

摘录(该属性将业务模型从业务模型转换为视图模型):

[AutoMap(typeof(Product), typeof(ShowProduct))]
public ActionResult Details(int id)
{
    var product = _productRepository.GetById(id);

    return View(product);
}

0
投票

如其他答案所述,AutoMapper是一个很好的解决方案。

但是您也可以编写扩展方法以将您的实体转换为ViewModel,反之亦然。也许这对于实体和模型类较少的小型项目会更好。

实施例:

public static class Extension
{
    public static MyViewModel ToModel(this MyEntity x)
    {
        return new MyViewModel
        {
            Id = x.Id,
            Name = x.FirstName + " " + x.LastName,
            UserId = x.User?.Id
        };
    }
}

并使用:

// NOTE: "MyEntityTable" is of type "MyEntity"

List<MyViewModel> toReturn = _db.MyEntityTable
                  .Include(x => x.User) // Include other tables to join.
                  .Select(x => x.ToModel())
                  .ToList();
© www.soinside.com 2019 - 2024. All rights reserved.