MVC 3 应用程序中的模型、视图模型、DTO [英] Models, ViewModels, DTOs in MVC 3 application

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

问题描述

我有一个包含两个子项目的网络解决方案(在 VS2010 中):

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

  1. Domain 包含 Model 类(通过实体框架映射到数据库表)和 Services(除了其他东西)负责 CRUD 操作

  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

WebUI 引用域项目

对于我创建的第一个页面,我直接将域项目中的模型类用作强类型视图中的模型,因为这些类很小,我想显示和修改所有属性.

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.

现在我有一个页面,它应该只处理相应领域模型的所有属性的一小部分.我通过在我的服务类中使用查询结果的 projection 来检索这些属性.但是我需要投射到一个类型 - 这里是我关于我能想到的解决方案的问题:

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. 我介绍了 ViewModels,它存在于 WebUI 项目中并公开 IQueryablesEF 数据上下文 从服务到 WebUI 项目.然后我可以直接投影到那些 ViewModel 中.

  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.

如果我不想公开 IQueryables 和 EF 数据上下文,我将 ViewModel 类放在 Domain 项目中,然后我可以返回 ViewModels直接作为来自服务类的查询和预测的结果.

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.

除了 WebUI 项目中的 ViewModels 之外,我还引入了 Data transfer objects,它从查询中移动数据ViewModels 的服务类.

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.

解决方案 1 和 2 的工作量相同,我倾向于使用解决方案 2 将所有数据库问题保留在一个单独的项目中.但不知何故,在域项目中使用 View-Models 听起来是错误的.

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.

解决方案 3 听起来需要做更多的工作,因为我有更多的类要创建和关注 Model-DTO-ViewModel 映射.我也不明白 DTO 和 ViewModel 之间有什么区别.ViewModel 不正是我想要显示的 Model 类的选定属性的集合吗?它们不会包含与 DTO 相同的成员吗?为什么我要区分 ViewModel 和 DTO?

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?

提前感谢您的反馈!

编辑(因为我的文字墙可能太长了,有人要求我提供代码)

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

示例:我有一个 Customer 实体 ...

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
}

... 并且想要创建一个视图,该视图仅显示(并且可能允许编辑)列表中客户的 Name.在服务类中,我通过投影提取视图所需的数据:

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

然后是一个带有操作方法的 CustomerController.这应该是什么样子?

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

要么这样 (a) ...

Either this way (a) ...

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

... 或者更好的方式 (b):

... or better this way (b):

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

    List<SomeClass2> newList = CreateNewList(list);

    return View(newList);
}

关于上面的选项 3,我想说:SomeClass1(位于 Domain 项目中)是 DTOSomeClass2(存在于 WebUI 项目中)是一个 ViewModel.

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.

我想知道区分这两个类是否有意义.为什么我不总是为控制器操作选择选项 (a)(因为它更容易)?除了 DTO (SomeClass1) 之外,是否还有理由引入 ViewModel (SomeClass2)?

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)?

推荐答案

介绍存在于WebUI 项目并公开 IQueryables和来自 EF 数据上下文WebUI 项目的服务.然后我可以直接投射到那些视图模型.

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.

问题在于,您很快就会在使用 EF 试图展平"模型时遇到问题.当我有一个看起来像这样的 CommentViewModel 类时,我遇到了类似的事情:

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

以下 EF4 查询投影到 CommentViewModel 不会像 无法将 ToString() 方法转换为 SQL:

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

使用 Automapper 之类的东西是一个不错的选择,尤其是当您要进行大量转换时.但是,您也可以创建自己的转换器,基本上将您的域模型转换为您的视图模型.就我而言,我创建了自己的扩展方法来将我的 Comment 域模型转换为我的 CommentViewModel,如下所示:

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

我所做的基本上是执行标准的 EF 查询以带回域模型,然后使用扩展方法将结果转换为视图模型.例如以下方法说明用法:

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

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

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