我有我的域模型(用于绑定EF并用于映射到数据库):
public class Category : BaseEntity
{
public string Name { get; set; }
public Category ParentCategory { get; set; }
//Code removed for brevity
}
然后我有一个共享控制器在我的视图中显示一个类别菜单:
@Html.Action("GetCategoryMenu", "Shared")
控制器
[OutputCache(Duration = int.MaxValue, VaryByParam = "none")]
public ActionResult GetCategoryMenu()
{
var viewModel = new CategoryMenuViewModel
{
Categories = _categoryService.Get().Where(c => c.ParentCategory != null && c.ParentCategory.Id == WebsiteContext.CurrentWebsite.CategoryId)
};
return PartialView("_CategoryMenu", viewModel);
}
ViewModel:
public class CategoryMenuViewModel
{
public IEnumerable<Category> Categories { get; set; }
}
我现在的问题是,如果我在我的视图中实现了category.GetUrl()
之类的内容,那会是什么?域模型是否适合这样的事情?
GetUrl()
会根据某些条件运行一些逻辑并返回一个Url。我看到这是从视图本身使用嵌入到超链接。它将按类别运行,基本上只是获取一个Url,以防我想改变以后生成它们的方式。
基本上,我试图在部分视图中实现这一点,以呈现类别菜单:
@foreach (Category category in Model.Categories)
{
<li class="list-group-item clearfix">
<a href="@category.GetUrl()"><i class="fa fa-angle-right"></i> @category.Name</a>
</li>
}
我现在只是在寻找最佳实践建议,因为我想确保我正确理解MVC模式,因为我对将GetUrl()
方法放在我的域模型上有一种奇怪的感觉,但我不知道为什么。
答案 0 :(得分:2)
我现在的问题是,如果我在我的视图中实现了类似category.GetUrl()的内容,那会是什么?域模型是否适合这样的事情?
没有!如果明天你的公司决定写一个IPad应用程序怎么办?您的域模型仍然有效 - 业务逻辑和权限检查以及所有这些仍然适用 - 但您不再使用URL。显然,URL生成逻辑不属于此。
在ASP.NET MVC中,生成URL的责任通常在于UrlHelper类的方法。通常,直接使用这些方法很容易:
<a href="@Url.Action("Category", new{category.Id})"><i class="fa fa-angle-right"></i> @category.Name</a>
但是如果您需要重复使用代码,我建议您在UrlHelper上以扩展方法的形式执行此操作:
<a href="@Url.Category(category)"><i class="fa fa-angle-right"></i> @category.Name</a>
答案 1 :(得分:1)
基本思想是以这样一种方式创建应用程序,即可以替换彼此之上的层而不触及底层。一个典型的例子就是three-tier architecture。这意味着您的GUI只访问逻辑层(业务模型),而您的逻辑层只访问数据库层(实体框架)。由于实体框架的设计方式,最后一部分有点可疑:当您将业务逻辑放入实体类本身时,EF已经将逻辑层与数据层混合在一起。
但是,对于上面两层,你应该尊重这种分离。执行GUI任务的方法(例如GetUrl
)不应该是域类的一部分。它可能是例如在将来你需要更改GUI,你的URL现在有不同的布局。然后,您需要更改域模型,而不是它应该如何。
正确的方法是创建一个额外的视图模型,然后将业务对象所需的属性映射到视图模型。但是,您真的想避免这种情况,您可能会考虑在GUI项目中为业务类定义扩展方法。
旁注:我完全按照您的建议行事,即使用通过Entity Framework获得的业务对象作为视图模型。请注意这带来的限制,特别是在将更改保存回EF时。您通常仍需要映射发布给您的对象,即使它们是实体,因为它们由MVC模型绑定器实例化,并且不通过EF上下文检索,即它们不能保存为现有对象的更新版本。解决这个问题的一种方法可能是创建一个自定义模型绑定器,但我认为通过创建视图模型和映射会更好。