在我的ASP.NET MVC应用程序中,我使用工作单元和存储库模式进行数据访问。
使用工作单元类和其中定义的存储库,我将在控制器中获取相关的实体集。凭借我的初学者知识,我可以想到两种获取业务模型并将其转换为视图模型的方法。
目前我正在使用第一种方法,但是对于具有大量属性的视图模型,我的控制器代码开始看起来很丑陋。
另一方面,我在想,因为我的存储库名为UserRepository(例如),它应该直接返回业务模型,而不是仅对单个视图有用的模型。
您认为哪一项是大型项目的更佳实践?还有另一种方法吗?
感谢。
答案 0 :(得分: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)将其转换为视图模型并将其替换为视图。该视图当然是对视图模型的强类型。
答案 1 :(得分:3)
我认为您的存储库应该返回业务模型。
然后,您可以使用Automapper之类的工具自动将属性映射到您的viewmodel,并可以摆脱手动映射代码。如果您不希望公开所有业务权限的属性,或者它的结构是视图,那么这种方法非常有用。
你也可能会发现这个post很有帮助,你可以摆脱手动映射调用(排序),它也提供了一个很好的例子,如何使用viewmodels等(在我看来) - 或者得到至少某种灵感。
摘自帖子(该属性执行转换形式busioness模型到viewmodel):
[AutoMap(typeof(Product), typeof(ShowProduct))]
public ActionResult Details(int id)
{
var product = _productRepository.GetById(id);
return View(product);
}
答案 2 :(得分:0)
如其他答案所述,AutoMapper是一个很好的解决方案。
但是,您也可以编写扩展方法以将Entity转换为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();