5

目前,我得到了非常糟糕的视图模型。

类看起来像这样=>

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

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

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

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

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


当视图需要来自多个聚合根的数据时,我感到困惑。我正在创建具有图书馆、阅读器、书目记录等实体的应用程序。

在我的情况下 - 在域级别,将所有这 3 种类型分组LibraryReaderThatHasOrderedSomeBooks或诸如此类是没有意义的,但是应该显示关于特定图书馆中特定读者的订购书籍列表的视图需要它们全部。

OrderedBooksList所以 -用OrderedBooksListModel下面的视图模型和LibraryOutput视图模型创建视图似乎很好。甚至更好的视图模型,它利用展平技术并具有诸如等的道具。ReaderOutputBibliographicRecordOutputOrderedBooksListModelReaderFirstNameLibraryName

但这会导致映射问题,因为输入不止一个。
这不再是 1:1 的关系,我只踢一个聚合根。
这是否意味着我的域模型有点错误?

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

在这种情况下,每个人都会这样做吗?

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

我不愿意这样做=>

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

好像写了很多。:)


此刻正在阅读这篇文章。而这个


行。我对这个问题想了很多,是的 - 添加另一个抽象层似乎是一个解决方案 =>

替代文字

所以 - 在我看来,这已经奏效了,现在是玩弄的时候了。

泰吉米

4

3 回答 3

4

在我们为替代方案苦苦挣扎了很长时间之后,我们突然想到了一件事情:渲染数据与接收数据不同

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

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

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

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

我们使用抽象映射器和服务将 PostModel 映射到域对象 - 如有必要,然后可能会映射回 ViewModel。

于 2010-01-07T13:36:14.657 回答
4

很难定义所有这些,但这里有。我们喜欢将我们称之为 View 看到的内容与 Controller 构建的内容分开。视图看到了一个扁平的、脑死亡的类似 DTO 的对象。我们称之为视图模型。

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

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

于 2010-01-11T13:42:40.200 回答
3

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

正如我们以特别适合特定应用程序的方式构建表示域数据的自定义 ViewModel 一样,我们还使用自定义表示层服务来根据需要组合事物。这些服务更加临时,因为它们的存在只是为了支持给定的视图。

通常,我们会将此服务隐藏在接口后面,以便具体实现可以自由使用它需要的任何不相关的注入域对象来组合所需的结果。

于 2010-01-07T14:41:55.290 回答