如何处理具有多个聚合根的视图模型?

时间:2010-01-07 13:16:44

标签: asp.net-mvc viewmodel automapper

目前,我的视角模型非常糟糕。

类看起来像这样=>

 public class AccountActionsForm
    {
        public Reader Reader { get; set; }
        //something...
    }

问题是Reader类型来自域模型(违反SRP)。

基本上,我正在寻找设计技巧(即将视图模型拆分为输入/输出是一个好主意吗?)如何使我的视图模型无摩擦且开发人员友好(即 - 映射应该使用控制器自动工作基类)?

我知道AutoMapper框架,我很可能会使用它。

那么,再一次 - 尝试创建正确的视图模型时常见的问题是什么?如何构建它?当需要多域对象输入时如何进行映射?


当视图需要来自多个聚合根的数据时,我感到很困惑。我正在创建具有Library,Reader,BibliographicRecord等实体的应用程序。

在我的情况下 - 在域级别,将所有这3种类型分组到LibraryReaderThatHasOrderedSomeBooks或诸如此类的内容是没有意义的,但是应该显示特定库中特定读者的有序书籍列表的视图需要它们。< / p>

所以 - 使用OrderedBooksList视图模型创建视图OrderedBooksListModel似乎很好,其中包含LibraryOutputReaderOutputBibliographicRecordOutput视图模型。甚至更好 - OrderedBooksListModel视图模型,它利用flattening technique并拥有ReaderFirstNameLibraryName等道具。

但这导致了映射问题,因为有多个输入 它不再是1:1的关系,我只在一个聚合根中开始。
这是否意味着我的域模型是错误的?

那么纯粹存在于UI层的视图模型字段(即表示选中标签的枚举)呢?

this在这种情况下每个人都做了什么?

 FooBarViewData fbvd = new FooBarViewData();
   fbvd.Foo = new Foo(){ A = "aaa"};
   fbvd.Bar = new Bar(){ B = "bbb"};
   return View(fbvd);

我不愿意这样做=&gt;

var fbvd = new FooBarViewData();
   fbvd.FooOutput =  _mapper.Map<Foo,FooOutput>(new Foo(){ A = "aaa"});
   fbvd.BarOutput = _mapper.Map<Bar,BarOutput>(new Bar(){ B = "bbb"});
   return View(fbvd);

似乎很多写作。 :)


目前

Reading this。并this


确定。我经常考虑这个问题,是的 - 添加另一个抽象层似乎是一个解决方案=&gt;

alt text

所以 - 在我看来这已经有效了,现在是时候进行一些玩弄了。

吉米

3 个答案:

答案 0 :(得分:4)

在我们长期以来一直在努力寻找替代方案之后,这是我们遇到的一个问题:渲染数据与接收数据不同

我们使用ViewModels来呈现数据,但很快就发现,当通过表单发布和类似方式接收数据时,我们无法真正使ViewModel符合ModelBinding的概念。主要原因是浏览器的往返通常会导致数据丢失。

例如,即使我们使用ViewModel,它们也基于来自真实域对象的数据,但它们可能不会公开来自域对象的所有数据。这意味着我们可能无法立即从浏览器发布的数据中重建底层域对象。

相反,我们需要使用映射器和存储库从发布的数据中检索完整的域对象。

在我们意识到这一点之前,我们在尝试实现可以​​从发布的数据重建完整的域对象或ViewModel的自定义ModelBinder时遇到了很多困难,但现在我们有单独的 PostModels 来模拟我们如何接收数据

我们使用抽象映射器和服务将PostModel映射到域对象 - 然后在必要时返回ViewModel。

答案 1 :(得分:4)

很难定义所有这些,但这里有。我们希望将我们称之为View的内容从Controller构建的内容中分离出来。视图看到一个扁平的,脑死亡的类似DTO的物体。我们称之为视图模型。

在Controller方面,我们构建了构建View Model所需内容的丰富图表。这可能只是一个聚合根,也可能是几个聚合根的组合。所有这些结合在一起我们称之为演示模型。有时,表示模型只是我们的持久性(域)模型,但有时它完全是一个新对象。然而,我们在实践中发现,如果我们需要构建一个复合的表示模型,它往往会成为相关行为的磁铁。

在您的示例中,我将创建一个ViewFooBarModel和一个ViewFooBarViewModel(或ViewFooBarModelDto)。然后,我可以在我的控制器中讨论ViewFooBarModel,然后依靠映射来使用AutoMapper从这个中间模型中展平我需要的东西。

答案 2 :(得分:3)

虽然将不相关的实体(或者更确切地说是他们的存储库)分组到域对象或服务中可能没有意义,但在Presentation层中对它们进行分组可能会很有意义。

正如我们以特别适合特定应用程序的方式构建表示域数据的自定义ViewModel一样,我们也使用自定义表示层服务,根据需要组合事物。这些服务更具特色,因为它们仅用于支持给定视图。

通常,我们会将此服务隐藏在接口后面,以便具体实现可以自由地使用构成所需结果所需的无关注入域对象。