如果实体处于某种状态,如何强制执行约束,例如任何字段(或特定字段)都不得更改?

2023-11-29

我正在尝试在当前项目(c#、mvc、nhibernate、castle)中使用 DDD,并且我正在考虑检查约束的最佳方法,该约束表明如果实体处于某种状态,任何字段(或特定字段)都不得更改, IE。已预订的发票(状态=已预订)不得更改金额字段。在服务层中,我得到一些 DTO 对象(来自 gui 或 web 服务等),我需要将其映射到域对象。映射完成后,我想验证我的对象 - 特别是我想检查我的问题中的特定约束。

目前我在想:

  • 跟踪实体级别的更改,即在每个 setter 上将字段添加到更改的字段集合中,并切换 NHibernate 以使用字段访问策略。如果不允许更改值,此模式的变体将在 setter 上抛出异常
  • 在映射之前创建对象的副本并比较原始值和映射值
  • 依靠 nhibernate 并从 nhibernate 会话获取此信息 - 但是该规则不会在实体级别强制执行(恕我直言,它会破坏 ddd)

你怎么看待这件事?您知道这方面有什么好的模式吗?或者我是否遗漏了一些东西,我需要改变我对这个限制的思考方式?

预先感谢您的帮助。


DDD 中的域对象是“自我验证的”。换句话说,客户端代码不可能破坏域规则,因为对象强制执行其内部不变量。例如:

public class Invoice {
    private Money _amount;
    private InvoiceState _state;

    public void ChangeAmount(Money newAmount) {
        if(_state == State.Booked) {
            throw new InvalidOperationException(
                      "Unable to change amount for booked invoice.");
        }
        _amount = newAmount;
    }

    // Methods like this can be used by external code (UI) to check business
    // rules upfront, to avoid InvalidOperationException.
    public Boolean CanChangeAmount() {
        if(_state == State.Booked) {
            return false;
        }
        return true;
    }
}

另一个例子来自DDD样本:

  public HandlingEvent(final Cargo cargo,
                       final Date completionTime,
                       final Date registrationTime,
                       final Type type,
                       final Location location,
                       final Voyage voyage) {

    ...

    if (type.prohibitsVoyage()) {
      throw new IllegalArgumentException(
                       "Voyage is not allowed with event type " + type);
    }

永远不要让你的 UI 框架将域对象视为哑数据容器。不幸的是,互联网上的大量示例以及 C# 对 getter 和 setter 的强调都鼓励了这一点。如果您更改对象状态而不强制执行业务规则,您最终将得到“损坏”的对象。对于 NHibernate 来说尤其如此,因为它的 Session 会“记住”所有对象,并且会在下次提交或刷新时将它们转储到数据库中。但这只是一个技术问题,主要原因是您需要能够仅通过查看 Invoice 类来推理 Invoice 相关的业务规则。另请注意,代码应基于无处不在的语言。您应该看到“发票”、“预订”、“金额”等字样,而不是通用的“字段”、“财产”、“验证器”。

更新:empi,感谢您重述您的问题。您可能想提出一个新问题。这是我强调的引用

正如我在一条评论中所说 - 这个问题是一个更大的问题的一部分 我遇到的问题。我正在寻找定义域的标准方法 仅在域中的逻辑和约束,然后将其转换为 GUI 和其他层。我没有看到以下任何常见模式 常见需求:域声明该字段不可编辑,并且这 规则自动转换为GUI逻辑禁用该字段 并使其只读。我正在寻找 mvc 堆栈中的示例解决方案。我 感觉就像我在重新发明轮子,而大多数开发人员只是放弃 并复制 gui 中的逻辑

我认为您正在寻找一种方法来陈述域中的所有内容,然后“生成”UI。就像是裸露物体 for MVC?我从未使用过这种方法,但我怀疑生成的 UI 是否会赢得美观或可用性竞赛。在我看来,UI 中总会有一些业务逻辑的“重述”。一些领域不变量太复杂,涉及多个领域,需要存储库,甚至可能需要外部服务。我不确定是否可以自动生成高质量的用户界面。我认为尝试这样做可能会开始改变你的模型以符合 UI 基础设施。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果实体处于某种状态,如何强制执行约束,例如任何字段(或特定字段)都不得更改? 的相关文章

  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐