Dis*_*ile 19 c# asp.net-mvc entity-framework repository-pattern viewmodel
我是MVC和实体框架的新手,我有一个关于正确/首选方式的问题.
我一直在关注Nerd Dinner MVC应用程序,因为我正在编写这个应用程序.我有一个页面,其中包含来自几个不同地方的数据.它显示来自几个不同表的详细信息,并且还具有查找表中的下拉列表.
我创建了一个包含所有这些信息的ViewModel类:
class DetailsViewModel {
public List<Foo> DropdownListData { get; set; }
// comes from table 1
public string Property1 { get; set; }
public string Property2 { get; set; }
public Bar SomeBarObject { get; set; } // comes from table 2
}
Run Code Online (Sandbox Code Playgroud)
在Nerd Dinner代码中,他们的例子有点过于简单化了.DinnerFormViewModel采用单个实体:Dinner.根据晚餐,它根据晚餐地点为各国创建一个SelectList.
由于简单,它们的数据访问代码也非常简单.他有一个简单的DinnerRepository,其方法名为GetDinner().在他的行动方法中,他可以做一些简单的事情:
Dinner dinner = new Dinner();
// return the view model
return View(new DinnerFormViewModel(dinner));
Run Code Online (Sandbox Code Playgroud)
要么
Dinner dinner = repository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
Run Code Online (Sandbox Code Playgroud)
我的查询比这复杂得多,从多个表中提取...创建一个匿名类型:
var query = from a in ctx.Table1
where a.Id == id
select new { a.Property1, a.Property2, a.Foo, a.Bar };
Run Code Online (Sandbox Code Playgroud)
我的问题如下:
我的存储库类应该是什么样的?存储库类是否应该返回ViewModel本身?这似乎不是正确的做事方式,因为ViewModel意味着它正在视图中使用.由于我的查询返回一个匿名对象,如何从我的存储库返回它,以便我可以在我的控制器操作中构建ViewModel?
Kal*_*exx 10
虽然大多数答案都很好,但我认为他们缺少你问题的中间部分.
首先,没有100%正确的方法可以解决这个问题,我也不会太熟悉使用的确切模式的细节.随着应用程序变得越来越developped你会看到一个什么样的工作,什么不是,并找出如何最好地将其更改为您和您的应用程序.我刚刚做了彻底改变了我的Asp.Net MVC后端的格局,主要是因为很多建议,我发现不工作我试图做的.
话虽这么说,看看他们应该做什么的你的图层.存储库层仅用于添加/删除/编辑数据源中的数据.它不知道如何使用这些数据,坦率地说它并不关心.因此,存储库应该只返回您的EF实体.
其他人似乎缺少的部分问题是您需要在控制器和存储库之间添加一个额外的层,通常称为服务层或业务层.该层包含由控制器调用的各种类(但是您希望组织它们).这些类中的每一个都将调用存储库来检索所需的数据,然后将它们转换为控制器最终将使用的视图模型.
这个服务/业务层是您的业务逻辑所在(如果您考虑它,将实体转换为视图模型是业务逻辑,因为它定义了您的应用程序实际上将如何使用该数据).这意味着您不必调用特定的转换方法或任何东西.我们的想法是告诉您的服务/业务层您想要做什么,它会为您提供业务实体(视图模型),您的控制器不了解实际的数据库结构或如何检索数据.
服务层也应该是调用存储库类的唯一层.
您是正确的,存储库不应返回视图模型.由于对视图的更改将导致您更改数据层.
您的存储库应该是聚合根.如果你的property1,property2,Foo,Bar以某种方式相关,我会提取一个新类来处理这个问题.
public class FooBarDetails
{
public string Property1 {get;set;}
public string Property2 {get;set;}
public Foo Foo {get;set;}
public Bar Bar {get;set;}
}
var details = _repo.GetDetails(detailId);
Run Code Online (Sandbox Code Playgroud)
如果Foo和Bar根本不相关,则可能会选择引入服务来编写FooBarDetails.
FooBarDetails details = _service.GetFooBar(id);
Run Code Online (Sandbox Code Playgroud)
哪里GetFooBar(int)会是这个样子:
_fooRepo.Get(id);
_barRepo.Get(id);
return new FooBarDetails{Foo = foo, Bar = bar, Property1 = "something", Property2 = "something else"};
Run Code Online (Sandbox Code Playgroud)
这一切都是猜想,因为存储库的设计实际上取决于您的域.使用通用术语使得很难在对象之间建立潜在的关系.
如果我们正在处理订单的聚合根,则从评论更新.订单将包含OrderItem以及下订单的客户.
public class Order
{
public List<OrderItem> Items{get; private set;}
public Customer OrderedBy {get; private set;}
//Other stuff
}
public class Customer
{
public List<Orders> Orders{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
您的仓库应该返回一个完全水合的订单对象.
var order = _rep.Get(orderId);
Run Code Online (Sandbox Code Playgroud)
由于您的订单包含所需的所有信息,因此我会将订单直接传递给视图模型.
public class OrderDetailsViewModel
{
public Order Order {get;set;}
public OrderDetailsViewModel(Order order)
{
Order = order;
}
}
Run Code Online (Sandbox Code Playgroud)
现在拥有一个只有一个项目的视图模型可能看起来有点过分(而且最有可能是最初的).如果您需要在视图上显示更多项目,它将开始提供帮助.
public class OrderDetailsViewModel
{
public Order Order {get;set;}
public List<Order> SimilarOrders {get;set;}
public OrderDetailsViewModel(Order order, List<Order> similarOrders)
{
Order = order;
SimilarOrders = similarOrders;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10484 次 |
| 最近记录: |