基类(Domain Model)转换为派生类(View Model)

时间:2011-04-08 19:26:30

标签: c# asp.net-mvc-3

我在MVC应用程序中看到以下模式,其中基本上派生类为域类添加了次要功能,很多时候只显示依赖于基类中其他属性的只读属性。什么是不必编写基本属性复制代码(between //***** //*****)?

的更好方法
//Can't change this class, it has what is shown (it contains only properties)
public class MyDomainModel
{
    public bool BoolValue { get; set; }

    public string Prop1 { get; set; }
    public int Prop2 { get; set; }
    // Several other properties
}

public class MyViewModel : MyDomainModel
{
    // This is the only property that is added to the view model class
    public string DisplayValue
    {
        get { return BoolValue ? "Value1" : "Value2"; }
    }

    public static MyViewModel FromBase(MyDomainModel myDomainModel)
    {
        var myViewModel = new MyViewModel();

        //*****
        myViewModel.BoolValue = myDomainModel.BoolValue;
        myViewModel.Prop1 = myDomainModel.Prop1;
        myViewModel.Prop2 = myDomainModel.Prop2;
        // Several other properties
        //*****

        return myViewModel;
    }
}

// some other place

MyDomainModel myDomainObject = CallService();

//Here MyDomainModel needs to be converted to MyViewModel
MyViewModel myViewObject = MyViewModel.FromBase(myDomainObject);

编辑:我想要这个问题来解决在应用程序中传播过多“属性复制”代码的问题。不幸的是,错误的示例选择(从DomainModel派生的ViewModel)导致了另一个领域的讨论。

4 个答案:

答案 0 :(得分:1)

public class MyDomainModel
{
    // .....
}

public class MyViewModel : MyDomainModel
{
    // .....
}

为什么您的View Model会继承您的域模型? 这似乎是一个可怕的想法。

在这种情况下,遗产会给你带来什么好处?你在重用什么?

我只能看到一大堆属性,在您的使用场景中,您甚至无法重用这些属性(因为您获得了已经实例化的基类,并且您无法将其实例化更改为派生类)。

这里(通常)似乎合适的公理是“赞成合成而不是继承”。除非您有明确的理由和继承权,否则请避免使用。

最常见的建议是让ViewModel完全独立于类并保持它们的依赖性。它们应该是简单的POCO。

然后,您只需将域模型对象映射到视图模型对象。这将涉及一些重复的属性复制代码或使用像AutoMapper这样的工具,但你想要这里的复制,因为它减少了耦合。

另一方面,继承引入了一些非常紧密的耦合,这几乎肯定会给你带来麻烦。

答案 1 :(得分:0)

在基础中创建一个复制构造函数。

这将在派生类中为您节省大量代码。

public class MyDomainModel
{
    public bool BoolValue { get; set; }

    public string Prop1 { get; set; }
    public int Prop2 { get; set; }

    public MyDomainModel(MyDomainModel myDomainModel)
    {
        var myViewModel = new MyViewModel();

        //*****
        this.BoolValue = myDomainModel.BoolValue;
        this.Prop1 = myDomainModel.Prop1;
        this.Prop2 = myDomainModel.Prop2;
        // Several other properties
        //*****
    }
}

public class MyViewModel : MyDomainModel
{
    // This is the only property that is added to the view model class
    public string DisplayValue
    {
        get { return BoolValue ? "Value1" : "Value2"; }
    }

    public MyViewModel (MyDomainModel other) : base(other) {}
}

然后在代码中使用:

// some other place

MyDomainModel myDomainObject = CallService();

//Here MyDomainModel needs to be converted to MyViewModel
MyViewModel myViewObject = new MyViewModel(myDomainObject);

答案 2 :(得分:0)

这看起来类似于在渲染视图之前要将信息附加到所有模型的模式。实际上,您可以通过覆盖OnActionExecuted然后将数据附加到模型来实现此目的。

 protected override OnActionExecuted(ActionExecutedContext context)
 {
      ViewResult viewResult = filterContext.Result as ViewResult;

      if(viewResult != null)
      {
           MyDomainModel model = viewResult.ViewData.Model as MyDomainModel;

           if(model != null)
              /* Set Properties on your Model, for any model deriving 
                 from MyDomainModel! */
      }
 } 

答案 3 :(得分:0)

我认为你违反了单一责任原则,因为ViewModel的责任只是为了在没有任何业务逻辑的情况下从域模型中呈现视图中的一些数据而在这个类视图中模型类通常代表 一个DTO对象,你可以将Domain对象的数据映射到ViewModel对象中使用 AutoMapper

查看以下文章示例Automaper NerdDinner

AutoMapper: the Object-Object Mapper