在CQRS中,我的阅读方应该返回DTO还是ViewModels?

时间:2011-10-12 23:23:55

标签: c# cqrs

我正与我的同事就CQRS应用程序的阅读方面进行辩论。

选项1:我的CQRS应用程序的应用程序读取端返回DTO,例如:

public interface IOrderReadService
{
    public OrderDto Load(int id);
}

public class SomeController
{
    public ActionResult SomeAction(int id)
    {
        var dto = ObjectFactory.GetInstance<IOrderReadService>().Load(id);
        var viewModel = Mapper.Map<OrderDto, SomeViewModel>();
        return View(viewModel);
    }
}

public class SomeOtherController
{
    public ActionResult SomeOtherAction(int id)
    {
        var dto = ObjectFactory.GetInstance<IOrderReadService>().Load(id);
        var viewModel = Mapper.Map<OrderDto, SomeOtherViewModel>();
        return View(viewModel);
    }
}

选项2:应用程序读取端返回ViewModels,例如:

public interface IOrderReadService
{
    public SomeViewModel LoadSomething(int id);
    public SomeOtherViewModel LoadSomethingElse(int id);
}

public class SomeController
{
    public ActionResult SomeAction(int id)
    {
        return View(ObjectFactory.GetInstance<IOrderReadService>().LoadSomething(id));
    }
}

public class SomeOtherController
{
    public ActionResult SomeOtherAction(int id)
    {
        return View(ObjectFactory.GetInstance<IOrderReadService>().LoadSomethingElse(id));
    }
}

从我的同事和我在这件事上所做的研究看,反应看起来好坏参半 - 看起来它真的取决于背景。所以我问你,亲爱的StackOverflowians:

一种方法似乎比其他方法有明显的优势吗?如果是这样,他们是什么?

4 个答案:

答案 0 :(得分:30)

一般建议是每个屏幕一个投影(Greg Young),甚至每个小部件一个投影(如果我正确理解Udi Dahan)。

要将读取模型合并到DTO中,再次必须将其映射到单独的视图,这与优化的读取模型的整体目的相矛盾。它增加了我们试图摆脱的复杂性和映射步骤。

我的建议:如果在瘦读取层中使用NoSQL,请尝试尽可能接近SELECT * FROM ViewSpecificTable [WHERE ...]或类似的东西。

聚合根的概念及其“子”在读取方面没有太多含义,因为这些是域模型概念。您不希望在读取端具有域模型,它只存在于写入端。

Mohamed Abed提到的特定于UI平台的转换应该在UI层中完成,而不是在读取模型本身中完成。

长话短说:我选择选项2.为了不将它与特定于平台的ViewModel混淆,我宁愿称之为ReadModel,但每个视图都有一个。

答案 1 :(得分:13)

DDD / CQRS的主要原则之一是您不应该编辑视图模型。相反,基于任务的屏幕应引导用户发出显式命令。如果你不能提出基于任务的屏幕,你应该使用不同形式的CQRS,就像我在这里描述的那样:

http://udidahan.com/2011/10/02/why-you-should-be-using-cqrs-almost-everywhere/

答案 2 :(得分:5)

我更愿意返回DTO将应用层与表示技术分开(因为每个表示技术可能对表示模型的结构有一些要求),例如web MVC应用程序绑定与WPF MVVM绑定不同,也可能要求视图模型中的某些属性/字段与应用程序数据无关,例如(SliderWidth或IsEmailFieldEnabled,...)。 另外,例如,如果使用WPF MVVM,我需要实现INotifyPropertyChanged接口以允许绑定,在应用程序读取服务中实现此接口不方便也无关联。

所以我更希望将读取数据表示的关注与实际的表示技术和视图模型分开。

所以选项1对我来说更好

答案 3 :(得分:3)

读取模型是写入模型的投影。它是为了实现特定目的。在您的情况下,似乎为您的MVC控制器提供视图模型。因此,为什么要通过映射DTO到Viewmodels的麻烦?我能想到的唯一原因是拥有两个独立的读取模型的好处可能不会超过其维护成本。但是考虑到“合并”读取模型以达到“重用”和“降低维护成本”的目的会增加开发人员的复杂性(我可以更改此表吗?嗯,我现在有两个(或更多)消费者我需要考虑帐户 - 再次闻起来有点像数据库集成。)

只是我的想法。