【问题标题】:Custom Field Design with C# and RavenDB使用 C# 和 RavenDB 进行自定义字段设计
【发布时间】:2013-07-12 20:17:26
【问题描述】:

我面临一个与如何将自定义字段附加到系统中的实体相关的关键设计问题。实体用 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 的特殊标识符。”
  • 类型:文字
  • 选项: null

我面临的第一个问题是在 Book 的每个实例上存储什么。选择范围从...

低端:

仅存储 CFD Id 和实例值

高端:

将整个 CFD 连同值一起存储

“低端”很糟糕,因为如果不拉入另一个文档中的 CFD,我就无法显示一本书。此外,如果我以任何方式更改 CFD,我就会更改历史文档中值的含义。

“高端”不好,因为会有很多重复。对于选择列表 CFD,CFD 可能非常繁重,因为定义包含所有可选选项。

第一个问题是... 每本书应该在文档中存储多少? 刚好足以显示这本书(我必须返回 CFD 来显示如果我要允许用户编辑 CF 值的选项和描述)?

第二个问题是...... 我应该将一种实体类型的整个 CFD 集合存储在一个文档中,还是将每个 CFD 保存在它自己的文档中?

作为文档的每个 CFD 都让每个 CFD 的事情变得简单(尤其是当我开始执行诸如停用定义之类的操作时),但是我需要一种方法来将 Book CFD 与 Author CFD 区分开来。每当我想编辑实体时,这也迫使我为附加到实体的每个 CF 加载 1 个文档。

一个文档中给定类型的所有 CFD 只允许我加载一个文档,但随后我也加载了所有已停用的定义。

第三个问题... 有没有更好的方法来实现这一点?

第四个问题... 是否有任何示例或开源解决方案,这样我就不必重新发明这个轮子?

【问题讨论】:

  • 您是否探索过使用dynamic 获取自定义数据?
  • 另外,每个Book 是否共享同一组自定义字段?那些领域的选项呢,每本书可能会有所不同吗?
  • Matt,在任何给定的时间点,每本书都共享同一组自定义字段,但该组可能会随着时间而改变。因此,去年的一本书可能与今天的一本书有不同的字段。
  • 如果一年后我看一本书,我看到了今天存在的字段,可以吗?如果我只有来自不再存在的字段的数据怎么办?还是我应该只看到去年图书添加到系统时存在的字段和选项?
  • 我认为一年前的书应该显示一年前的自定义字段。

标签: c# architecture nosql ravendb aggregateroot


【解决方案1】:

既然你在cmets中说:

...一年前的图书应该显示一年前的自定义字段。

我只能看到两个可行的选项。

选项 1

  • 自定义字段定义存在于它们自己的文档中。
  • 每本书都包含一份适用于该书的自定义字段定义的副本,以及每个自定义字段的选定值。
  • 它们在图书首次创建时被复制,但可以根据您的逻辑再次复制。也许在编辑时,您可能想要获取一个新副本,这可能会使当前的选择无效。
  • 优点:独立,易于索引和操作。
  • 缺点:自定义字段定义的副本很多。存储需求可能非常大。

选项 2

  • 使用Temporal Versioning Bundle(免责声明:我是它的作者)。
  • 自定义字段定义仍然存在于它们自己的文档中,但它们会被临时跟踪。这意味着对自定义字段的修订将保留在可用历史记录中。
  • 书籍仅包含选定的值。它们不包含定义的副本。
  • 书籍不需要进行临时跟踪,但它们的数据中确实需要某种有效日期。也许是“输入”日期。使用任何对你有意义的东西。
  • 账面到差价合约的关系是Nt:Tx 类型。您可以找到此关系类型here 的另一个示例。您可能想了解temporal relationships 的概述,以便对此有所了解。请注意,这是一个棘手的主题,很快就会变得复杂。
  • 优点:所需的存储空间少得多,因为自定义字段定义数据的重复副本并不多。
  • 缺点:学习曲线。处理时态数据的复杂性。在您的数据库服务器上安装自定义包的要求。

使用 either 选项,我只需在自定义字段定义中保留一个属性,说明它适用于什么类型(书籍、作者等)。

【讨论】:

    猜你喜欢
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多