【问题标题】:Command > Rich Model > Event pattern in MVC命令 > 富模型 > MVC 中的事件模式
【发布时间】:2014-06-22 19:41:23
【问题描述】:

我正在创建一个试图避免Fat Controller 气味的 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);
    }
}

我的问题是,用户提交的表单需要允许编辑整个联系人,即所有相关的地址、电话号码等),这意味着每个属性状态都需要一个命令和一个处理程序改变。

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

我已经考虑了一些选择...

  1. 可以将每个可能的子命令(即单独的 ChangeHomeAddressCommand)的实例添加到其中的“宏”命令(可能称为 EditContactCommand)。宏命令加载聚合并将其传递给子命令并在 dispose 时提交更改。

  2. 使 UI 更加“以任务为中心”。编辑页面不是一个结构化的文本框集合来收集输入,而是使用带有“更改”按钮的标签,该按钮调用一个模式对话框。当模态对话框确定时,将 AJAX 回传到控制器,控制器反过来总线命令。或者实际上,构建仅公开联系人聚合的某些方面的较小页面。您只会更改实际更改的内容,并且更改可以在没有大的“保存”式提交的情况下发生。 (我不确定用户是否会穿这个,因为他们似乎喜欢他们的文本框海洋!)

我将不胜感激任何建议、经验和智慧。谢谢。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 domain-driven-design cqrs


    【解决方案1】:

    问题可能在于您正在努力取消对本质上非常 CRUD 的应用程序(就我们可以从那段小代码而言)进行取消 CRUD 化。

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

    我认为修改整个实体的命令没有任何问题,只要它们是由您的领域专家探索的有效领域操作/事件,并且不是 100%。应用程序很少是纯粹的 CRUD,但当它们是,DDD 肯定不是最好的选择方法。

    【讨论】:

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

    你可能已经在角落里画自己了。我错过了用户的意图。为什么要更改家庭住址?是用户打错了还是联系人真的移动了?如果是后者,您可能需要发送电子邮件 - 如果是前者,可能不需要。

    让场景驱使您发现用户的意图。

    【讨论】:

      猜你喜欢
      • 2011-03-10
      • 1970-01-01
      • 2020-05-30
      • 1970-01-01
      • 2016-01-30
      • 1970-01-01
      • 2023-03-28
      • 2017-07-15
      • 2020-11-22
      相关资源
      最近更新 更多