【发布时间】:2019-09-26 12:30:49
【问题描述】:
我将尝试用一个过于简单的例子来说明我的问题: 想象一下,我有一个这样的域实体:
public class Box
{
public int Id { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public int Depth { get; set; }
public int Volume => Height * Width * Depth;
}
我正在根据其他所有属性进行计算(体积)。 现在说我想使用 Entity Framework Core 存储这个类。当我持久化实体时,有什么方法可以让 EF 核心将 Volume 的当前值存储在自己的列中?
这是我的核心问题。我不允许分享我的实际代码,但这里有一些关于我的真实世界实体的更深入的信息(我们称之为“盒子”):
- My Box 有 18 个属性,其中 6 个是子实体的集合,定义了与这些实体的一对多关系,因此您可以将其称为聚合根。
- 每个属性(包括子实体集合)都构成一个“总计”,我们称之为“体积”,它作为公共属性公开。每当更改属性或添加或删除子实体时,卷都会更改。
- 在我看来,我需要列出每个 Box,但我只需要显示 5 个属性,其中一个是卷,这就是为什么我想在每次持久化实体时将其存储在数据库字段中.
关于如何解决这个问题的一些想法:
- 完全水合每个盒子,计算每个盒子的体积,然后将其投影到一个摘要中。这包括将每个盒子的所有七个表与子实体连接起来,为每个盒子进行计算并投影到简化的视图模型。对我来说,要获得一个我在坚持时就知道的数字,这似乎是很多开销。
- 为 Box 和所有子实体创建一个“持久性 DTO”,然后在存储时将 Volume 的结果映射到 dto 上的卷自动属性。仅存储一个数字似乎也有很多开销,而且似乎与 EF 的工作方式完全不一致。我只想坚持我的实体。
- 我可以在 Box 上进行正确的 OO 并为每个属性创建私有字段和正确的设置器,以便在调用设置器时更新私有卷字段。这还包括在 Box 上编写用于操作所有子实体集合的方法,并将它们呈现为只读集合。这会导致在每个 setter 上产生大量开销的私有字段和代码重复,但看起来确实比上述替代方案更“谨慎”。
- 我可以将 Volume 转换为 CalculateVolume() 方法并使用 fluent API 创建一个 Volume-property,然后在上下文的 SaveChanges() 覆盖中填充该属性。但是覆盖 SaveChanges 是我不喜欢做的那种 EF 工作。
- 我可以这样做:
public class Box
{
public int Id { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public int Depth { get; set; }
public int Volume {
get => CalculateVolume();
private set => _volume = value; }
private int _volume;
private int CalculateVolume() => Height * Width * Depth;
}
这似乎确实符合我的要求,但由于某种原因感觉像是在作弊,并污染了我的域实体。此外,我不确定这实际上是否适用于所有情况,但这是我在撰写本文时首选的解决方案。
我希望能够使用 fluent API 进行配置。我注意到 PropertyBuilder.ValueGeneratedOnAdd() 方法描述说“该值可能由客户端值生成器生成,也可能由数据库生成作为保存实体的一部分。”,但我找不到任何示例客户端价值生成。
欢迎任何合理的反馈。
编辑: 澄清一下:实际计算非常复杂,使用来自 7 个不同表的值。还对所涉及的每个属性进行加权。开头的 Box 示例过于简化,仅用于说明目的。可以说,我需要将计算保留在我的代码中。我只想存储结果。
【问题讨论】:
标签: c# .net-core entity-framework-core