Asp.net mvc MVC中的命令>丰富模型>事件模式

Asp.net mvc MVC中的命令>丰富模型>事件模式,asp.net-mvc,asp.net-mvc-4,domain-driven-design,cqrs,Asp.net Mvc,Asp.net Mvc 4,Domain Driven Design,Cqrs,我正在创建一个ASP.NET MVC应用程序,试图避免这种气味。我通过使控制器方法简单地将轻量级命令发送到命令总线,然后由命令处理程序接收命令总线来实现这一点。命令处理程序在域模型上执行命令,从而创建持久化的状态更改事件 我这样做是为了尝试摆脱从存储库获取X的CRUD模型,对其进行更改并将其放回原处,从web应用程序中删除所有特定于领域的知识,并允许将用户的意图直接传达给领域模型 所以,假设一个Contact聚合是按如下方式组成的,为了简洁起见,我省略了除了一个setter方法之外的所有方法 p

我正在创建一个ASP.NET MVC应用程序,试图避免这种气味。我通过使控制器方法简单地将轻量级命令发送到命令总线,然后由命令处理程序接收命令总线来实现这一点。命令处理程序在域模型上执行命令,从而创建持久化的状态更改事件

我这样做是为了尝试摆脱从存储库获取X的CRUD模型,对其进行更改并将其放回原处,从web应用程序中删除所有特定于领域的知识,并允许将用户的意图直接传达给领域模型

所以,假设一个Contact聚合是按如下方式组成的,为了简洁起见,我省略了除了一个setter方法之外的所有方法

public class Contact {

    private Address _homeAddress;

    public Address HomeAddress { 
        get { return _homeAddress; }
        set {
            if(newHomeAddress.Equals(_homeAddress)) return;
            _homeAddress = newHomeAddress;
            AddEvent(new HomeAddressChanged(Id, _homeAddress));
        }
    }

    public Address WorkAddress { get; set; }

    public PhoneNumber PhoneNumber { get; set; }

    public EmailAddress EmailAddress { get; set; }
}
执行HomeAddress更改的命令处理程序如下所示

public class ChangeHomeAddressCommandHandler : IHandleCommand<ChangeHomeAddressCommand>
{
    private IRepository<Contact> _repo;

    public ChangeHomeAddressCommandHandler(IRepository<Contact> repo) 
    {
        _repo = repo;
    }

    public void Execute(ChangeHomeAddressCommand command)
    {
        var toEdit = _repo.One(command.Id);
        toEdit.HomeAddress = command.NewHomeAddress;
        _repo.CommitChanges(toEdit);
    }
}
我的问题是,用户提交的表单需要允许编辑整个联系人,即其所有关联地址、电话号码和c,这意味着每个属性状态更改都需要一个命令和一个处理程序

每个处理程序都需要加载聚合,进行更改,然后提交更改。因此,即使不更改所有属性,命令处理程序仍然必须加载和构建联系人聚合四次,这是不必要的昂贵

我考虑过一些选择

一个名为EditContactCommand的宏命令,其中可以添加每个可能的子命令(即单个ChangeHomeAddressCommand)的实例。宏命令加载聚合并通过子命令传递聚合,并在dispose上提交更改

使UI更加专注于任务。编辑页面不是收集输入的文本框的结构化集合,而是使用标签和调用模式对话框的更改按钮。当模态对话框确定后,向控制器发回一个AJAX post,该控制器依次发送一个命令。或者确实,构建更小的页面,只暴露联系人聚合的某些方面。您只能更改实际更改的内容,并且更改可以在不进行大的保存样式提交的情况下进行。我不确定用户是否会戴上它,因为他们似乎喜欢他们的文本框海洋


我将非常感谢您的建议、经验和智慧。谢谢。

问题可能在于,您正在努力对一个应用程序进行解构,而我们从这段本质上非常粗糙的小代码中可以看出这一点

无论您如何尝试弯曲您的命令,使它们看起来不那么像CRUD,如果它们不描述域的真实性,它们就没有任何意义——这只会增加更多不必要的复杂性。如果更改电子邮件地址触发了重新发送验证电子邮件等整个过程,则更改电子邮件地址本身可能是一个命令,但如果它只是修改电子邮件字段,则不会


我认为修改整个实体的命令没有错,只要它们是有效的域操作/事件,并且不是100%的域操作/事件都是由域专家研究的。应用程序很少是纯粹的CRUD,但当它们是CRUD时,DDD肯定不是最好的选择。

你可能已经把自己逼到了墙角。我错过了用户的意图。为什么家庭住址要改变?用户是否输入了错别字,或者联系人是否真的移动了?如果是后者,你可能需要发送一封电子邮件——如果是前者,可能不是


让我们来驱动您发现用户的意图

谢谢。这是一个有用的观察,如果没有域上下文,我同意很难进行仲裁。我只想说,我的领域中确实存在一些现实情况,它们作为命令比观察简单的CRUD状态变化更有意义,并且随着需求的出现,我希望确保我不会把自己画进一个角落——例如,如果用户突然决定在电话号码发生变化时需要做些什么,如果这些意图已经分离,那就容易多了。至少我是这么告诉自己的!在保证复杂性/挠头和假设以后必须将一个命令拆分为多个命令之间,我随时都会选择后者。但也许只有我,而我不在你的项目中。