这是我最近需要做的常见事情,我正在寻找任何常见的模式,以使这更容易。
这一切的主要要点是我有一些数据模型,它们被建模以满足ORM并且纯粹对对象进行CRUD操作。这些模型目前通过存储库/工厂公开(取决于其C或RUD)。
然后我有了一个更具可读性的视图模型,并且有一些UI问题,例如视图之间的验证和映射数据(这是一个ASP.MVC场景,但这种情况可以抽象到大多数情况)。
所以我想说我去了localhost / user / 1,它应该让我在数据库中找到ID为1的用户,然后在UI上显示它。最终,这必须从数据域中提取数据,然后将其映射到ui模型以用于显示目的。
以下是一个示例场景:
public class OrmUser
{
public int Id {get;set;}
public string Name {get;set;}
public IList<Permission> Permissions {get;set;}
}
public class UiUser
{
[Required]
public int Id {get;set;}
[Required]
public string Name {get;set;}
public bool IsUserAdmin {get;set;}
}
public class UserMapper : IMapper<UiUser>
{
public UiUser Get(int id)
{
var ormUser = UserRepository.Get(id);
var uiUser = new UiUser
{
Id = ormUser.Id,
Name = ormUser.Name,
IsUserAdmin = IsUserAdmin(ormUser.Permissions)
}
}
private bool IsUserAdmin(IList<Permission> permissions)
{
return permissions.SomeLinq(ToFindIfTheyAreAnAdmin);
}
}
这是一个简单的例子,但显示了数据模型如何包含许多相同类型的信息,但在这个有问题的视图中,您并不关心所有信息只是其中的一部分。这种方式有一个映射器,你不仅可以抽象映射,还可以抽象与数据域的通信,但是你需要为每种类型编写一个映射器类,而上面假设它是单向映射,而不是双向映射需要更多代码。
那么你们如何进行这种映射呢?目前我刚刚编写抽象映射器,它基本上允许UI层运行查询,并返回一个视图模型,抽象存储库和从一个模型到另一个模型的复制数据,它只是觉得应该有一个更好的这样做的方法。
答案 0 :(得分:5)
在.net中你应该看看Automapper
https://github.com/AutoMapper/AutoMapper
它基本上允许你这样做:
CreateMap<Domain.Customer, ViewModel.Customer>()
然后您可以通过说:
在两者之间进行映射var vmCustomer = Mapper.Map<Domain.Customer, ViewModel.Customer>(domainCustomer);
它可能会为您节省大量的锅炉铭牌代码。
答案 1 :(得分:2)
是。 AutoMapper是适合您的工具。关于这一点的文章很多,但请到源头 - 吉米博加德。他是AutoMapper背后的主人。
请参阅此博客文章http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
AutoMapper现在几天以非常有效的方式支持MVC,你可以使用属性来装饰你的类。应该做什么映射。
/最好的问候Magnus
答案 2 :(得分:1)
在这种特殊情况下,我可能只是在我的表示层中为User编写扩展方法。
public static class UserPresentationExtensions{
public bool IsAdmin(this User user){
return permissions.SomeLinq(ToFindIfTheyAreAnAdmin);
}
}
视图看起来像这样:
@model User
<fieldset>
<legend>User: @Model.Name</legend>
@if(user.IsAdmin()){
User is an admin
}
</fieldset>
为避免重复导入名称空间,请使用web.config:
<configuration>
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="MyProject.PresentationExtensions" />
...
您有一点,但是假设您要为模型添加验证,因此您决定在Name属性中添加[Required]属性。虽然如果你使用共享模型,那么你的数据层需要知道注释,如果你的数据层必须有一些属性你的UI层需要知道它们。在最简单的情况下,你是对的,有时候让一个模型成为事实更容易,只是以不同的方式访问它,但是对于大多数复杂的项目,你会发现自己弄脏双方试图保存几行代码。
我说 - 在这个特殊情况下。这种方法仅适用于映射不值得且只有单向通信(您只需要渲染它)。
当谈到接收帖子时,它会有所不同。大多数“一刀切”的方法都是应用所谓的Thunderdome principle。那就是:
所有Controller方法都接受一个ViewModel对象(在某些情况下为零对象)并返回单个ViewModel对象(一个对象进入,一个对象离开)。
但是,我经常更喜欢使用extension / html帮助方式,只需将参数传递给这样的动作:
public void BatheCat(int id /* cat id */, int bathId, string shampoo){
...
}
如果参数计数失控(我不打扰,而它是&lt; = 3),我只是封装 他们(我的项目here's an example)。