使用 Entity Framework Core 时的不可变对象

Immutable objects when working with Entity Framework Core

总的来说,我对 oop 和编程还比较陌生,但有一件事我不明白,在使用像 EF 核心这样的关系数据库时,你是否应该有不可变对象。 如果我使用私有 setter 设置属性,这样我只能在创建这些对象时赋值,我该如何更改它们的状态? 我是否创建一个新的空对象,然后复制每个需要保持不变的属性,并只用 myObject.property = updatedValue 更新其中的一些属性? 我是否使用工厂以正确的值实例化该对象? 这不是因为有 public setter 而违反了 oop 原则吗?

我遇到过这个问题,例如当服务器和客户端交换数据并且客户端对这些数据进行处理时。当数据returns,有一个dtoclass,我还需要更新保存在数据库中的相关数据

如果您谈论的是不可变对象,那么不,您不会更新它们的值,并且如果该对象发生更改,您将不得不创建一个全新的实例,这就是使它们不可变的原因。但是,如果您试图封装一个可以更改状态的实体,并希望更改该实体的值,那么您通常会在该对象上使用命令方法来更改属性的值以提供封装,我相信你正在拍摄。

过去,当我使用 ORM 走类似的路线时,我在数据层有数据实体(classes)有 public getter 和 setter,而 ORM 会实例化对象并毫无问题地填充它们,然后我的存储库会将它们映射到具有私有 setter 的业务层 classes。我相信我使用 automapper 来执行此操作,并且它与私有 setter 的映射没有问题。

然后从 UI 交互的角度来看,要更新模型,业务实体将具有特定的命令方法,而不仅仅是一个包罗万象的“更新”方法。诸如“UpdateAddress”、“makePayment”之类的东西。这些方法将更新 class 的适当私有变量并向下过滤到数据实体,然后到数据库。

我确实认为很多这可能是矫枉过正,具体取决于您正在处理的内容,很多应用程序大多是 CRUD 应用程序,不需要很多业务规则。在那种情况下,我个人不会担心私人二传手之类的,除非它对你有意义。

EF Core 确实支持不变性,更具体地说,它可以利用实体​​的构造函数。这使您能够为您的实体创建纯粹不可变的属性(只有 getter,它生成只读支持字段),甚至整个实体都可以是不可变的。

需要考虑的几点:

  • EF 默认情况下 excludes/ignores 所有仅具有 getter 的属性。它假定它们是计算属性。对于这些属性,我们应该显式配置 EF 以将它们包含在模型中。
  • 如果我们在模型中包含只读属性,EF 将需要一个构造函数(它可能被标记为私有),其中包含与这些属性匹配的参数。您必须有一个只接受这些属性参数的构造函数,不包括可变参数。
  • 构造函数参数的命名应与属性完全相同。除第一个字符外,命名区分大小写。对于给定的 FirstName 属性,您可以将参数定义为 FirstName 或 firstName,但不能定义为 firstname。这是一个常见的错误。
  • 如果您已将不可变的拥有类型(例如,值对象)定义为实体的一部分,您可能不得不将它们添加为构造函数参数。这样做将是一个不正确的配置,并且您将面临运行时异常。 EF Core 分别创建这些对象的实例,并具有将这些对象映射到实体的不同内部机制。

我已经在这个blog post中详细阐述了。