【发布时间】:2011-08-25 02:33:42
【问题描述】:
我有一个包含两个子项目的 Web 解决方案(在 VS2010 中):
Domain包含Model类(通过实体框架映射到数据库表)和Services(除了其他东西)负责 CRUD 操作WebUI引用域项目
对于我创建的第一页,我在强类型视图中直接使用域项目中的模型类作为模型,因为这些类很小,我想显示和修改 所有 属性.
现在我有一个页面,它应该只适用于相应领域模型的所有属性的一小部分。我通过在我的服务类中使用查询结果的 投影 来检索这些属性。但是我需要投射到一个类型中 - 我的问题是关于我能想到的解决方案:
我介绍了
ViewModels,它存在于WebUI项目中,并将IQueryables和EF data context从服务公开到WebUI 项目。然后我可以直接投影到那些 ViewModel 中。如果我不想公开 IQueryables 和 EF 数据上下文,我将
ViewModel类放在Domain项目中,然后我可以直接返回 ViewModel 作为查询和投影的结果服务类。除了
WebUI项目中的ViewModels,我还介绍了Data transfer objects,它将数据从服务类中的查询移动到ViewModels。
解决方案 1 和 2 看起来工作量相同,我更喜欢解决方案 2 以将所有数据库问题保留在单独的项目中。但不知何故,在 Domain 项目中拥有 View-Models 听起来是错误的。
解决方案 3 听起来需要做更多的工作,因为我要创建更多类并关心 Model-DTO-ViewModel 映射。我也不明白 DTO 和 ViewModel 之间有什么区别。 ViewModels 不正是我想要显示的模型类的选定属性的集合吗?它们不会包含与 DTO 相同的成员吗?为什么要区分 ViewModel 和 DTO?
这三种解决方案中哪一种更可取,有哪些优点和缺点?还有其他选择吗?
提前感谢您的反馈!
编辑(因为我的文字墙可能太长并且被要求提供代码)
示例:我有一个Customer 实体...
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public City { get; set; }
// ... and many more properties
}
...并且想要创建一个仅显示(并且可能允许编辑)列表中客户的Name 的视图。在服务类中,我通过投影提取视图所需的数据:
public class CustomerService
{
public List<SomeClass1> GetCustomerNameList()
{
using (var dbContext = new MyDbContext())
{
return dbContext.Customers
.Select(c => new SomeClass1
{
ID = c.ID,
Name = c.Name
})
.ToList();
}
}
}
然后有一个带有操作方法的 CustomerController。这应该是什么样子?
无论哪种方式(a)...
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
return View(list);
}
...或者更好的方式(b):
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
List<SomeClass2> newList = CreateNewList(list);
return View(newList);
}
关于上面的选项 3,我想说:SomeClass1(位于 Domain 项目中)是一个 DTO,SomeClass2(位于 WebUI 项目中)是一个 视图模型。
我想知道区分这两个类是否有意义。为什么我不总是为控制器操作选择选项(a)(因为它更容易)?除了 DTO (SomeClass1) 之外,是否还有理由引入 ViewModel (SomeClass2)?
【问题讨论】:
-
@jfar:现在有一个带有代码的示例。
-
我很好奇 - 您选择的方法对您有什么效果??
-
@qntmfred:我很满意。我现在使用 GET 请求的已接受答案中的方法(将 EF 模型直接投影到 ViewModel 的扩展方法,投影发生在 DB 中,不涉及 DTO)。对于 POST 请求,我将进入 POST 操作的 ViewModel 映射到 DTO,然后使用该 DTO 调用服务方法。 (我不直接映射到 EF 模型,因为有时会涉及到业务逻辑,我不想在表示层中有它,并且我不能将 ViewModel 用于服务,因为服务层不知道ViewModel 类。)
-
太棒了。感谢您的更新。
-
很好的问题,很好的讨论。好像您读懂了我的想法并发布了问题。谢谢!
标签: asp.net asp.net-mvc asp.net-mvc-3 architecture