MVC2 对何时使用视图模型或域对象的困惑
在遵循 Steve Sanderson 的 pro asp.net 框架书籍教程后,我成功地使用存储库模式获得了两个数据库对象的基本编辑和显示功能。
当我想显示/更新多个对象的属性时遇到问题。
我知道视图模型是实现此目的的一种方法,但我对何时应该使用视图模型以及它们如何与我的域模型对象相适应感到困惑。
例如,对于我的两个对象,我有存储库和以下方法来返回每个对象列表
public IQueryable<Customer> Customers
{
get { return customersTable; }
}
public IQueryable<CustomerSite> CustomerSites
{
get { return customerSitesTable; }
}
然后在我的控制器中,我将对象从存储库传递到视图,就像
public ViewResult List([DefaultValue(1)] int page)
{
var customerSitesToShow = customerSiteRepository.CustomerSites;
var customersToShow = customerRepository.Customers;
var viewModel = new CustomerSitesListViewModel
{
CustomerSites = customerSitesToShow.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
customers = customersToShow.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = customerSitesToShow.Count()
}
};
return View(viewModel); //Passed to view as ViewData.Model (or simply model)
}
}
我现在明白的那样,我可以使用视图模型来访问两个对象的属性一个视图,所以我有一个视图模型,其中包含两个对象的属性
{
public class SiteViewModel
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string AddressLine1 { get; set; }
}
public class CustomerViewModel
{
public int Id { get; set; }
public string CustomerName { get; set; }
public string PrimaryContactName { get; set; }
public SiteViewModel Site { get; set; }
}
}
然后是一个主视图模型,我将其强烈键入显示模板
public class CustomerSitesListViewModel
{
public IList<CustomerSite> CustomerSites { get; set; }
public PagingInfo PagingInfo { get; set; }
public IList<Customer> customers { get; set; }
public CustomerViewModel Customers { get; set; }
}
当我运行此命令时,会呈现显示模板,但我的客户集合是空的,因为我认为我需要 LINQ join 语句检索客户列表和客户网站? LINQ 连接是执行此操作的最佳方法吗?所以我可以从显示模板访问这两个对象,就像
<%= Html.DisplayFor(x => x.Customers.CustomerName) %>
<%= Html.DisplayFor(x => x.Customers.Site.AddressLine1) %>
这是我更困惑的地方,包含 LINQ 查询以返回客户集合的方法应该去哪里,应该在存储库中还是视图模型中?
After following the tutorial is Steve Sandersons pro asp.net framework book I have managed to get basic editing and display functionality for two database objects using the repository pattern.
I am having problems when i want to display/update properties from multiple objects.
I am aware that viewmodels are a way to do this but im confused as to when i should use a viewmodel and how they fit in with my domain model objects.
For example for my two objects i have repository's and the following methods to return each list of the objects
public IQueryable<Customer> Customers
{
get { return customersTable; }
}
public IQueryable<CustomerSite> CustomerSites
{
get { return customerSitesTable; }
}
Then in my controller im passing the objects from the repository to the view like
public ViewResult List([DefaultValue(1)] int page)
{
var customerSitesToShow = customerSiteRepository.CustomerSites;
var customersToShow = customerRepository.Customers;
var viewModel = new CustomerSitesListViewModel
{
CustomerSites = customerSitesToShow.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
customers = customersToShow.Skip((page - 1) * PageSize).Take(PageSize).ToList(),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = customerSitesToShow.Count()
}
};
return View(viewModel); //Passed to view as ViewData.Model (or simply model)
}
}
I now understand i can use a viewmodel to access properties for two objects in one view so i have one viewmodel with properties for my two objects
{
public class SiteViewModel
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string AddressLine1 { get; set; }
}
public class CustomerViewModel
{
public int Id { get; set; }
public string CustomerName { get; set; }
public string PrimaryContactName { get; set; }
public SiteViewModel Site { get; set; }
}
}
Then a master view model that i strongly type to a display template
public class CustomerSitesListViewModel
{
public IList<CustomerSite> CustomerSites { get; set; }
public PagingInfo PagingInfo { get; set; }
public IList<Customer> customers { get; set; }
public CustomerViewModel Customers { get; set; }
}
When i run this the display template is rendered but my customer collection is empty as i think i need a LINQ join statement to retrieve both the list of customers and the customer sites? Is a LINQ join the best way to do this? so i can access both objects from the display template like
<%= Html.DisplayFor(x => x.Customers.CustomerName) %>
<%= Html.DisplayFor(x => x.Customers.Site.AddressLine1) %>
This is where i get more confused, where should the method containing the LINQ query to return the customer collection should go, should this be in the repository or the view model?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
据我了解,您混淆了域对象所具有的两种不同的职责和视图模型的职责。
我不太清楚你的模型。客户是否拥有一个或多个站点?他们之间是什么关系?从我的角度来看,您可以在存储库级别执行哪些操作,在该级别执行。因此,我将直接从存储库返回客户及其站点,因为您可以使用联接在存储库级别聚合数据,并将其在一次往返中返回到数据库。
既然您知道需要在视图中聚合它们,为什么还要返回两个单独的实体 Customer 和 CustomerSite 呢?你制造的问题比必要的还要多。
因此,可以在映射到平面视图模型对象(例如称为 CustomerWithSite)之后立即从存储库返回 Customer 和 Site。为此,您可以使用 AutoMapper(http://automapper.codeplex.com/)。您还可以为视图创建一个“特殊”存储库,该存储库已返回针对存储库中的查询和投影发出的视图格式化的对象。由你决定。但不要将域对象用于视图目的。
我也不会在我的存储库之外公开 IQueryable。你会给自己带来麻烦。因为一旦您启用其他层来操作您的查询,存储库就不再对返回的内容负责。然后一些开发人员会尝试在视图中操作Iqueryable,但缺点是它需要打开与数据库的连接。从我的角度来看,保持连接开放并不是很好的设计。如果连接之前关闭了怎么办?在视图上显示对象时,您会收到 Dispose 异常。不太好。还要考虑可测试性。
我不知道你是否更清楚,但请注意我所说的缺点。
From what I understand you're confusing two different responsibilities the domain objects have and the one of the view model.
I don't see very well your model. Does the Customer has one site or more? What's the relationships between them? From my point of view what you can do a the repository level, do it at that level. So I would return a Customer with it's Site directly from the repository because you can aggregate data at repository level with joins and return it in one round-trip to the database.
Why bother returning two separate entities Customer and CustomerSite as you know that you need them agregated in your view ? You're creating more problems then necessary.
So returning Customer and Site from the repository at once, could be after mapped to the flat view model object for example called CustomerWithSite. For that you can use AutoMapper(http://automapper.codeplex.com/). You can have also a "special" repository for views that already returns an object formated for the view that is issue from the queries and projections in the repository. It's up to you. But don't use your domain object for the view purpose.
I also would not expose IQueryable outside my repository. You will get yourself in trouble. Because once, you enable other layers to manipulate your queries, the repository is no longer responsible about what is returned. Then some developpers would attempt to manipulate Iqueryable in the view, but the drawback is that it needs the connection to the database open. Not very good desgn from my point of view to keep the connection open for that. What if connection is closed before ? You would get Disposed exception while displaying objects on the view. No very good. Think also about testability.
I don't know if it's clearer for you but be aware of the shortcomings I'm talking about.