模型,的ViewModels,DTO的在MVC 3应用程序 [英] Models, ViewModels, DTOs in MVC 3 application

查看:174
本文介绍了模型,的ViewModels,DTO的在MVC 3应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Web解决方案(在VS2010)两个子项目:


  1. 持有的模式类(通过实体框架映射到数据库表)和服务其中(除其他的东西)负责CRUD操作


  2. WebUI中它引用域项目


有关我创建了第一页我从域项目直接作为示范在我的强类型的意见,因为类是小所使用的模型类,我想显示和修改的所有的特性

现在我有一个网页,其中只应与相应的域模型的所有属性的一小部分工作。我在我的服务类使用的投影的查询结果的检索这些属性。但我需要的项目成一个类型 - 这里来我对问题的解决方案,我能想到的:


  1. 我引进的ViewModels 这住在 WebUI中项目和揭露 IQueryables ,并从服务在WebUI项目 EF数据上下文。然后,我可以直接投射到这些的ViewModels。


  2. 如果我不希望暴露IQueryables,我把视图模型类中的域的EF数据上下文的项目,那么我可以返回的ViewModels直接从服务类的查询和预测的结果。


  3. 在除的ViewModels WebUI中的项目,我引进数据传输对象其中移动从查询数据在服务类的的ViewModels


解决方案1和2的样子相同数量的工作,我倾向于preFER溶液2,以保持在一个单独的项目中的所有数据库的担忧。但不知何故,这听起来错拥有的查看的-Models在域项目。

解决方案3听起来像一个大量的工作,因为我有更多的类来创建和关心模型DTO - 视图模型映射。我也想不明白会是什么的DTO和的ViewModels之间的差异。不是的ViewModels,我要展示我的模型类的所选属性的完全收藏?难道他们不会包含相同的成员的DTO的?为什么我要的ViewModels和DTO之间的区别?

这三个人的解决方案是preferable和有什么好处和缺点?是否还有其他选择?

感谢您的反馈意见提前!

修改(因为我的文字也许太长墙,并已要求code)

例如:我有一个客户实体...

 公共类客户
{
    公众诠释ID {搞定;组; }
    公共字符串名称{;组; }
    公共市{搞定;组; }
    // ...等等特性
}

......,想在列表中创建一个视图仅显示(也许允许编辑)名称客户。在服务类中提取我通过我的投影需要的视图中的数据:

 公共类的CustomerService
{
    公开名单< SomeClass1> GetCustomerNameList()
    {
        使用(VAR的DbContext =新MyDbContext())
        {
            返回dbContext.Customers
                。选择(C =>新建SomeClass1
                             {
                                 ID = c.ID,
                                 名称= c.Name
                             })
                .ToList();
        }
    }
}

再有就是用一个动作方法的CustomerController。这应该看起来怎么样?

无论这种方式(一)...

 公众的ActionResult指数()
{
    清单< SomeClass1>清单= _service.GetCustomerNameList();
    返回查看(名单);
}

...或更好的这种方式(二):

 公众的ActionResult指数()
{
    清单< SomeClass1>清单= _service.GetCustomerNameList();    清单< SomeClass2> newList = CreateNewList(名单);    返回查看(newList);
}

对于选项3以上我说: SomeClass1 (生命项目)是< STRONG> DTO 和 SomeClass2 (生命 WebUI中项目)是一个视图模型

我想知道,如果它曾经是有道理的区分两类。为什么不我总是选择控制器动作选项(A)(因为它更容易)?有没有理由引进视图模型 SomeClass2 )除了在 DTO SomeClass1 )?


解决方案

  

介绍一个住的ViewModels
  WebUI中的项目和揭露IQueryables
  从外汇基金数据上下文
  服务在WebUI项目。然后我
  可以直接投射到那些
  的ViewModels。


这个麻烦的是你很快就会碰上使用EF试图'扁平化'模式的问题。我遇到过类似的事情,当我有一个 CommentViewModel 类,它是这样的:

 公共类CommentViewModel
{
    公共字符串内容{搞定;组; }
    公共字符串dateCreated会获得{;组; }
}

以下EF4查询投影到 CommentViewModel 不会因为工作的couldn't的ToString()方法转换成SQL

  VAR评论=从C在DbSet那里c.PostId ==帖子ID
               选择新CommentViewModel()
               {
                   内容= c.Content,
                   dateCreated会= c.DateCreated.ToShortTimeString()
               };

使用类似Automapper是一个不错的选择,特别是如果你有很多的转换使。但是,您也可以创建自己的转换器,基本上你的域模型转换为您的视图模型。在我来说,我创建了自己的扩展方法,我的注释转换域模型到我的 CommentViewModel 是这样的:

 公共静态类ViewModelConverters
{
    公共静态CommentViewModel ToCommentViewModel(此评论评论)
    {
        返回新CommentViewModel()
        {
            内容= comment.Content,
            dateCreated会= comment.DateCreated.ToShortDateString()
        };
    }    公共静态的IEnumerable&LT; CommentViewModel&GT; ToCommentViewModelList(这IEnumerable的&LT;&评论GT;评论)
    {
        清单&LT; CommentViewModel&GT; commentModels =新的List&LT; CommentViewModel&GT;(comments.Count());        的foreach(在评论变种C)
        {
            commentModels.Add(c.ToCommentViewModel());
        }        返回commentModels;
    }
}

基本上我要做的就是执行一个标准的EF查询带回域模型,然后使用扩展方法的结果转换为一个视图模型。例如,下面的方法说明了使用

 公开征求意见GetComment(INT commentId)
{
    返回CommentRepository.GetById(commentId);
}公共CommentViewModel GetCommentViewModel(INT commentId)
{
    返回CommentRepository.GetById(commentId).ToCommentViewModel();
}公共IEnumerable的&LT;&评论GT; GetCommentsForPost(INT帖子ID)
{
    返回CommentRepository.GetCommentsForPost(帖子ID);
}公共IEnumerable的&LT; CommentViewModel&GT; GetCommentViewModelsForPost(INT帖子ID)
{
    返回CommentRepository.GetCommentsForPost(帖子ID).ToCommentViewModelList();
}

I have a web solution (in VS2010) with two sub-projects:

  1. Domain which holds the Model classes (mapped to database tables via Entity Framework) and Services which (besides other stuff) are responsible for CRUD operations

  2. WebUI which references the Domain project

For the first pages I've created I have used the Model classes from the Domain project directly as Model in my strongly typed Views because the classes were small and I wanted to display and modify all properties.

Now I have a page which should only work with a small part of all properties of the corresponding Domain Model. I retrieve those properties by using a projection of the query result in my Service class. But I need to project into a type - and here come my questions about the solutions I can think of:

  1. I introduce ViewModels which live in the WebUI project and expose IQueryables and the EF data context from the service to the WebUI project. Then I could directly project into those ViewModels.

  2. If I don't want to expose IQueryables and the EF data context I put the ViewModel classes in the Domain project, then I can return the ViewModels directly as result of the queries and projections from the Service classes.

  3. In addition to the ViewModels in the WebUI project I introduce Data transfer objects which move the data from the queries in the Service classes to the ViewModels.

Solution 1 and 2 look like the same amount of work and I am inclined to prefer solution 2 to keep all the database concerns in a separate project. But somehow it sounds wrong to have View-Models in the Domain project.

Solution 3 sounds like a lot more work since I have more classes to create and to care about the Model-DTO-ViewModel mapping. I also don't understand what would be the difference between the DTOs and the ViewModels. Aren't the ViewModels exactly the collection of the selected properties of my Model class which I want to display? Wouldn't they contain the same members as the DTOs? Why would I want to differentiate between ViewModels and DTO?

Which of these three solutions is preferable and what are the benefits and downsides? Are there other options?

Thank you for feedback in advance!

Edit (because I had perhaps a too long wall of text and have been asked for code)

Example: I have a Customer Entity ...

public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public City { get; set; }
    // ... and many more properties
}

... and want to create a View which only shows (and perhaps allows to edit) the Name of customers in a list. In a Service class I extract the data I need for the View via a projection:

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();
        }
    }
}

Then there is a CustomerController with an action method. How should this look like?

Either this way (a) ...

public ActionResult Index()
{
    List<SomeClass1> list = _service.GetCustomerNameList();
    return View(list);
}

... or better this way (b):

public ActionResult Index()
{
    List<SomeClass1> list = _service.GetCustomerNameList();

    List<SomeClass2> newList = CreateNewList(list);

    return View(newList);
}

With respect to option 3 above I'd say: SomeClass1 (lives in Domain project) is a DTO and SomeClass2 (lives in WebUI project) is a ViewModel.

I am wondering if it ever makes sense to distinguish the two classes. Why wouldn't I always choose option (a) for the controller action (because it's easier)? Are there reasons to introduce the ViewModel (SomeClass2) in addition to the DTO (SomeClass1)?

解决方案

introduce ViewModels which live in the WebUI project and expose IQueryables and the EF data context from the service to the WebUI project. Then I could directly project into those ViewModels.

The trouble with this is you soon run into problems using EF trying to 'flatten' models. I encountered something similar when I had a CommentViewModel class that looked like this:

public class CommentViewModel
{
    public string Content { get; set; }
    public string DateCreated { get; set; }
}

The following EF4 query projection to the CommentViewModel wouldn't work as the couldn't translate the ToString() method into SQL:

var comments = from c in DbSet where c.PostId == postId 
               select new CommentViewModel() 
               { 
                   Content = c.Content,
                   DateCreated = c.DateCreated.ToShortTimeString() 
               };

Using something like Automapper is a good choice, especially if you have a lot of conversions to make. However, you can also create your own converters that basically convert your domain model to your view model. In my case I created my own extension methods to convert my Comment domain model to my CommentViewModel like this:

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;
    }
}

Basically what I do is perform a standard EF query to bring back a domain model and then use the extension methods to convert the results to a view model. For example, the following methods illustrate the usage:

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();
}

这篇关于模型,的ViewModels,DTO的在MVC 3应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆