2010-01-07 44 views
5

目前,我得到了相当不好的视图模型。如何处理具有多个聚合根的视图模型?

类看起来像这样=>

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

问题是,阅读器类型来自域模型(违反SRP的)。基本上,我正在寻找设计技巧(即将视图模型分解为输入/输出是一个好主意?)如何使我的视图模型无摩擦和开发人员友好(即 - 映射应该自动工作控制器基类)?

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

因此,再次尝试创建正确的视图模型时常见的问题是什么?如何构建它?如何在需要多个域对象输入时完成映射?


我对查看需要来自多个聚合根的数据的情况感到困惑。我正在创建应用程序,其中包含图书馆,阅读器,书目记录等实体。

在我的情况下 - 在域级别,将所有这3种类型分组到LibraryReaderThatHasOrderedSomeBooks或什么都没有意义,但查看应显示列表为特定图书馆中的特定读者订购图书需要全部。

所以 - 它似乎罚款来创建OrderedBooksListModel视图模型视图OrderedBooksList下保存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); 

我不愿意这样做=>

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


好的。我想过这个问题有很多,是的 - 增加一个抽象层似乎是一个解决方案=>

alt text http://i46.tinypic.com/fe14qp.jpg

所以 - 在我的脑海这个已经工作,现在是时候为一些玩弄。

TY吉米

回答

3

这很难定义所有这些,但在这里。我们喜欢分离出我们称之为View从Controller构建的内容。该视图看到一个扁平的,脑死的DTO样物体。我们称之为视图模型。

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

在你的例子中,我会创建一个ViewFooBarModel和一个ViewFooBarViewModel(或ViewFooBarModelDto)。然后我可以在我的控制器中讨论ViewFooBarModel,然后依靠映射来使用AutoMapper从中间模型中得到我所需要的。

+0

希望看到你回答这个问题,你应该知道(http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/01/04/ui-automation-tools-snake-oil.aspx)。对于这个问题的回答只是成功开发好的和可靠的UI测试(并准备Mvc2模板嗡嗡声)的另一块砖块,我的实际目标是什么。当我回家时,我会尽量总结整个想法 - 然后在你的答案下张贴另一个“ping”评论以获得一些回应。 :) – 2010-01-11 15:05:20

4

下面是对我们明白,我们一直在与长一段时间挣扎的替代品后一个项目:渲染数据是从接收数据不同。

我们使用ViewModels来渲染数据,但很快就发现,当通过表单发布和类似的方式接收数据时,我们无法真正让ViewModel适合ModelBinding的概念。主要原因是往返于浏览器往往涉及数据丢失。作为一个例子,即使我们使用ViewModels,它们基于来自真实域对象的数据,但它们可能不公开所有来自域对象的数据。这意味着我们可能无法立即从浏览器发布的数据中重建基础域对象。

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

我们意识到这一点之前,我们努力与很多试图执行可能从重建发布数据全域对象或视图模型定制ModelBinders,但现在我们有独立的PostModels该模型中,我们如何接收数据。

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

+0

这是一个很好的提示,但不幸(或幸运地)我已经想出了这部分。 Id/Mapping的模型绑定就像一个魅力。另一件事 - 将视图模型分解为您呈现的视图模型并查看发布表单时收到的模型是很好的。 – 2010-01-07 13:52:26

+0

我很感兴趣,当查看需要多个实体视图模型并且需要分组时,如何处理这些案例。有关于此的任何提示? – 2010-01-07 13:54:32

+0

我不确定我是否理解其他问题,但是您可以从其他ViewModels创建ViewModels。然而,你是一个聪明的人,所以你可能已经知道,所以我想你的意思是别的...... – 2010-01-07 14:01:54

3

虽然将无关的实体(或者他们的存储库)组合到域对象或服务中可能没有意义,但将它们组合到表示层中可能会有很大的意义。

正如我们构建的自定义ViewModels以特别适合特定应用程序的方式表示域数据一样,我们还使用自定义表示层服务,根据需要组合事物。这些服务比较特殊,因为它们只是为了支持某个特定的视图而存在。

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

+0

这对我也有意义。我只是想知道从技术角度来看实际的实施。我不愿意创建无数的构造函数来聚合实体并产生更复杂的视图模型。 automapper可以在这方面提供一些帮助吗? – 2010-01-07 14:50:11

+0

我一直无法将我们的东西减少到某种不复杂的状态。对于富客户端来说更简单,因为您没有全部的往返和数据丢失。我没有看到AutoMapper在这方面提供了很多帮助,因为它的强制是基于约定的映射。也许你应该问这个具体的问题作为一个新的SO问题,然后我保证不回答:) – 2010-01-07 15:11:55

+0

想到一个想法=>可以用MapTo(typeof(OrderedBooksListModel))来修饰动作并调用匿名类型的视图'View(“OrderedBooksList”,new {library,reader,bibliographicrecord []})'然后 - 通过过滤器,使用一些反射魔术和自动映射器正确映射它。这是一个可接受的解决方案吗?有什么缺点? – 2010-01-07 16:11:35

相关问题