我面临一个与如何将自定义字段附加到系统中的实体相关的关键设计问题。实体用 C# 表示并保存在 RavenDB 中。我们大致关注领域驱动设计的租户,我们的实体是聚合根。
[注意:我想避免围绕 DDD 方法中的自定义字段等通用功能的适当性进行任何辩论。假设我们有一个合法用户需要向我们的实体附加和显示任意数据。此外,为了说明设计挑战,我已经将我的示例通用化。:)]
我的问题是关于如何最好地布置字段定义和字段值实例。
想象一个域,我们有 Book 和 Author 的聚合根。我们希望用户能够将任意数据属性附加到 Books 和 Authors 的实例。所以,我们可以用这样的类定义一个自定义字段:
public enum CustomFieldType
{
Text,
Numeric,
DateTime,
SingleSelect,
MultiSelect
}
public class CustomFieldDefinition
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public CustomFieldType Type { get; set; }
public Collection<string> Options { get; set; }
}
附加到Book的 CustomFieldDefinition (CFD)可能具有以下值:
- ID: “BookCustomField\1”
- 名称: “FooCode”
- 类型:文本
- 描述: “Foo Corp 的特殊标识符。”
- 类型:文本
- 选项:空
我面临的第一个问题是在 Book 的每个实例上存储什么。选择范围从...
低端:
仅存储 CFD Id 和实例值
至
高端:
将整个 CFD 与值一起存储
“低端”很糟糕,因为如果不拉入另一个文档中的 CFD,我就无法显示一本书。此外,如果我以任何方式更改 CFD,我就会更改历史文档中值的含义。
“高端”不好,因为会有很多重复。对于选择列表 CFD,CFD 可能非常繁重,因为定义包含所有可选选项。
第一个问题是……每本书的文档中应该存储多少?足以显示这本书(如果我要允许用户编辑 CF 值,我必须返回 CFD 以显示选项和描述)?
第二个问题是......我应该将一种实体类型的整个 CFD 集合存储在一个文档中还是将每个 CFD 保存在它自己的文档中?
作为文档的每个 CFD 使每个 CFD 的事情变得简单(尤其是当我开始执行诸如停用定义之类的操作时),但是我需要一种方法来将 Book CFD 与 Author CFD 分开。每当我想编辑实体时,这也迫使我为附加到实体的每个 CF 加载 1 个文档。
一个文档中给定类型的所有 CFD 只允许我加载一个文档,但随后我也加载了所有已停用的定义。
第三个问题......有没有更好的方法来实现这一点?
第四个问题......是否有任何示例或开源解决方案,所以我不必重新发明这个轮子?