【问题标题】:Where to convert business model to view model?在哪里将业务模型转换为视图模型?
【发布时间】:2012-07-13 12:04:19
【问题描述】:

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

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

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

目前我正在使用第一种方法,但是对于具有大量属性的视图模型,我的控制器代码开始变得丑陋且冗长。

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

对于大型项目,您认为哪一项是更好的做法?有其他方法吗?

【问题讨论】:

标签: c# asp.net-mvc entity-framework repository-pattern unit-of-work


【解决方案1】:

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

然后您可以使用Automapper 之类的工具自动将属性映射到您的视图模型,并且可以摆脱手动映射代码。如果您不想将所有业务实体的属性或其复杂结构暴露给视图,这种方法非常有用。

您还可能会发现这个post 很有帮助,您可以在其中摆脱手动映射调用(在某种程度上),它还提供了一个很好的示例,如何使用视图模型等(在我看来)-或者至少获得一些一种灵感。

摘自帖子(该属性将业务模型转换为视图模型):

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

    return View(product);
}

【讨论】:

  • 非常喜欢。达林的回答有点详细,所以我接受他的回答。希望你不要介意。
  • 谢谢,太好了。感谢您提供信息 - 我同意达林的答案具有相同的内容,但呈现得更好(因此是更好的答案)。我仍然建议您阅读该链接,因为 Viewmodels 等上可能还有其他有趣的信息。
  • @BernhardKircher 如何在同一个示例中选择特定列,因为有时我们只需要 2 或 3 列而不是表中的所有列
【解决方案2】:

存储库应该返回域模型,而不是视图模型。至于模型和视图模型之间的映射,我个人使用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)将其转换为视图模型并将其替换为视图。视图当然是视图模型的强类型。

【讨论】:

  • 非常喜欢。不知道Automapper。这是我的问题所需要的。
  • 自定义操作过滤器方法是否可测试?如果在单元测试中调用它,自动映射器将如何工作?
  • @JoshuaBarker,单元测试的全部意义在于您正在孤立地测试功能。那么你到底想在这里单独测试什么? AutoMap 属性?太好了,继续为此编写一个单元测试。还是将域模型传递给视图的控制器操作?太好了,继续为此编写一个单元测试。或者你的控制器动作是用 AutoMap 属性修饰的?太好了,继续为此编写一个单元测试。到目前为止,您已经编写了 3 个单元测试,其中包含验证控制器操作是否按预期工作所需的一切。
  • @DarinDimitrov 如何在同一个示例中选择特定列,因为有时我们只需要 2 或 3 列而不是表中的所有列。
【解决方案3】:

正如其他答案中提到的,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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    相关资源
    最近更新 更多