Sla*_*uma 16 architecture asp.net asp.net-mvc asp.net-mvc-3
我有一个带有两个子项目的Web解决方案(在VS2010中):
Domain它包含Model类(通过Entity Framework映射到数据库表),Services以及(除了其他东西)负责CRUD操作
WebUI 它引用了Domain项目
对于我创建的第一个页面,我在我强类型视图中直接使用Domain项目中的Model类作为Model,因为类很小,我想显示和修改所有属性.
现在我有一个页面,它只能用于相应域模型的所有属性的一小部分.我通过在Service类中使用查询结果的投影来检索这些属性.但我需要投射到一个类型 - 这里有我能想到的解决方案的问题:
我介绍ViewModels了WebUI项目中的哪些内容IQueryables以及EF data context从服务公开到WebUI项目.然后我可以直接投射到那些ViewModels.
如果我不想公开IQueryables和EF数据上下文,我将ViewModel类放在Domain项目中,那么我可以直接返回ViewModels作为来自Service类的查询和预测的结果.
除了ViewModels在WebUI我介绍项目Data transfer objects,其来自移动查询的数据在服务类的ViewModels.
解决方案1和2看起来像是相同的工作量,我更倾向于选择解决方案2来将所有数据库问题保存在单独的项目中.但不知何故,在Domain项目中使用View -Model 听起来是错误的.
解决方案3听起来更多的工作,因为我有更多的类来创建和关心Model-DTO-ViewModel映射.我也不明白DTO和ViewModels之间会有什么区别.ViewModels不是我想要显示的Model类的所选属性的集合吗?他们不会包含与DTO相同的成员吗?为什么我要区分ViewModels和DTO?
这三种解决方案中哪一种更可取,有哪些优点和缺点?还有其他选择吗?
感谢您提前的反馈!
编辑(因为我可能有太长的文本墙并且被要求提供代码)
示例:我有一个Customer实体...
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public City { get; set; }
// ... and many more properties
}
Run Code Online (Sandbox Code Playgroud)
...并且想要创建一个仅显示(并且可能允许编辑)Name列表中客户的视图.在Service类中,我通过投影提取View所需的数据:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后有一个带有动作方法的CustomerController.这应该怎么样?
这种方式(a)......
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
return View(list);
}
Run Code Online (Sandbox Code Playgroud)
......或更好的这种方式(b):
public ActionResult Index()
{
List<SomeClass1> list = _service.GetCustomerNameList();
List<SomeClass2> newList = CreateNewList(list);
return View(newList);
}
Run Code Online (Sandbox Code Playgroud)
关于上面的选项3,我会说:( SomeClass1生活在Domain项目中)是一个DTO和SomeClass2(生活在WebUI项目中)是一个ViewModel.
我想知道区分这两个类是否合理.为什么我不总是为控制器动作选择选项(a)(因为它更容易)?有没有考虑引进视图模型(SomeClass2除)DTO(SomeClass1)?
我会通过使用自动映射工具(如AutoMapper)为您进行映射来解决您的问题.在映射很容易的情况下(例如,如果一个类的所有属性都应映射到另一个类上具有相同名称的属性),AutoMapper将能够为您完成所有连接工作,并且您必须给出几行代码,注意两者之间应该有一个映射.
这样,您可以将您的实体放入其中Domain,并在您的WebUI某个地方(最好在其中WebUI或在其中的子命名空间中)定义几个视图模型类.您的视图模型实际上是 DTO,但您不必担心域和DTO类之间的转换过程.
注意:我强烈建议您不要直接将您的域实体提供给MVC Web UI的视图.您不希望EF一直"粘贴"到前端层,以防您以后想要使用EF以外的其他东西.
介绍生活在WebUI项目中的ViewModel,并将IQueryables和EF数据上下文从服务公开给WebUI项目.然后我可以直接投射到那些ViewModels.
这样做的问题是你很快就会遇到使用EF试图"压扁"模型的问题.当我有一个CommentViewModel看起来像这样的类时,我遇到了类似的东西:
public class CommentViewModel
{
public string Content { get; set; }
public string DateCreated { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
以下EF4查询投影CommentViewModel将无法正常工作,因为 无法将ToString()方法转换为SQL:
var comments = from c in DbSet where c.PostId == postId
select new CommentViewModel()
{
Content = c.Content,
DateCreated = c.DateCreated.ToShortTimeString()
};
Run Code Online (Sandbox Code Playgroud)
使用像Automapper这样的东西是一个不错的选择,特别是如果你要进行大量的转换.但是,您也可以创建自己的转换器,基本上将您的域模型转换为您的视图模型.在我的情况下,我创建了自己的扩展方法,将我的Comment域模型转换为我的CommentViewModel样子:
public static class ViewModelConverters
{
public static CommentViewModel ToCommentViewModel(this Comment comment)
{
return new CommentViewModel()
{
Content = comment.Content,
DateCreated = comment.DateCreated.ToShortDateString()
};
}
public static IEnumerable<CommentViewModel> ToCommentViewModelList(this IEnumerable<Comment> comments)
{
List<CommentViewModel> commentModels = new List<CommentViewModel>(comments.Count());
foreach (var c in comments)
{
commentModels.Add(c.ToCommentViewModel());
}
return commentModels;
}
}
Run Code Online (Sandbox Code Playgroud)
基本上我所做的是执行标准EF查询以恢复域模型,然后使用扩展方法将结果转换为视图模型.例如,以下方法说明了用法:
public Comment GetComment(int commentId)
{
return CommentRepository.GetById(commentId);
}
public CommentViewModel GetCommentViewModel(int commentId)
{
return CommentRepository.GetById(commentId).ToCommentViewModel();
}
public IEnumerable<Comment> GetCommentsForPost(int postId)
{
return CommentRepository.GetCommentsForPost(postId);
}
public IEnumerable<CommentViewModel> GetCommentViewModelsForPost(int postId)
{
return CommentRepository.GetCommentsForPost(postId).ToCommentViewModelList();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7737 次 |
| 最近记录: |