【问题标题】:Best way to create a data model with dynamic amount of properties in .NET在 .NET 中创建具有动态属性数量的数据模型的最佳方法
【发布时间】:2011-11-05 23:49:19
【问题描述】:

我正在编写一个数据访问层,我只想返回每个请求所需的数据。假设您总共可以检索 100 个属性,但一个正常的请求可能只需要其中的两个或三个。

所以我在请求中添加了一个参数,用于指定要返回的属性,并且只会从数据库中提取这些数据。

正常的请求将返回 1,000 - 10,000 行的列表。我现在最关心的是如何有效地退货。

数据将在我的 .NET 项目中“内部”使用,但也可能被序列化为 XML 和 JSON,因此我不希望有 98 个空属性,而实际上只有 2 个是填充数据。

那么,用于创建此模型的最佳技术(在性能和“开销大小”的情况下)是什么?

更新: 所以一个属性实际上可以有三个状态。如果它从未被要求,它应该以某种方式被删除,如果它被要求它应该是 null 或实际值。

【问题讨论】:

  • 这取决于您为实体考虑的 API 类型。
  • @Peter Forss:实体的数量很重要,但同样重要的是每个实体有多少属性(除了每个实体引用的实体,等等)。
  • @Doc Brown:嗯,有哪些 API?这是一种通用的数据检索 API,我们将在其中不断添加属性。
  • @casperOne:我的错,我实际上是指行,对于最终用户来说,它总是(99.9% 的时间)同一个实体(即使数据可能是从数据库中的不同表中检索到的) .
  • @Peter Forss:对于用户来说它可能是一个实体,但实体上有多少个属性?这可能会对性能产生不利影响,具体取决于每行有多少属性。还是每行只有一个属性,所有行都分配给实体?

标签: .net c#-4.0 datamodel


【解决方案1】:

虽然我同意Andrei's answer 很方便,但它肯定会对性能产生影响。如果您的数据是平坦的(而且确实如此,因为您最终是从数据库中提取的),那么您可以拥有一个 IEnumerable<IDictionary<string, object>>,其中 IEnumerable<T> 中的每一行都是 IDictionary<string, object> 包含该行中的值。

一开始比较笨拙,但它动态的;从结果集中添加或删除属性仍然有效。

它的性能也更高,因为您不会有 (1,000 to 10,000) * N 调用反射(1,000 到 10,000)行,乘以 N,每行上的属性数(如果每行有 100 个属性,那么这是对 Reflection 的 100,000 到 1,000,000 次调用,这些调用会加起来)。 DynamicDictionary 最终将键/值对存储在查找表中,但它使用反射(通过 DLR 优化,但这仍然是其核心)来获取查找表。

知道什么是属性(你说你在内部为你的项目使用它,所以你必须知道你想使用的属性是什么)。为此,您真的应该使用强类型的data transfer object,其属性都可以为空,代表数据库中的值;结果集中任何为 null 或不存在的内容都将设置为 null。结果集中不存在的值永远不会被设置。

这样,您没有反射,您可以进行编译时类型检查(这非常重要,使用DynamicObject 会导致运行时异常)和更好的性能。 p>

XML 或 JSON 中的序列化使用这两种方法都很简单,您只需序列化 null 值,或者根本不序列化属性(如果使用 XML,只需确保您的架构支持将元素作为选项)。

【讨论】:

  • 性能+1。但是如果我使用的是强类型 DTO,我如何判断该属性是否已设置?因为当我将结果序列化为 JSON/XML 时,我希望属性即使为 null 也能被序列化,所以我需要区分 null 和未设置。我考虑过为属性使用元数据,但这也是一些开销。
  • @Peter Forss:我不同意您的序列化必须具有值为 null 的属性。这就是模式的用途,用于定义属性的属性。您的架构将表明数据点可能存在,但是否必须填充它是另一回事。 JSON 文档从来都不是自描述的,并且它们没有模式,因此它们的序列化格式必须从一开始就考虑这些不一致。除非您将此作为正式要求(我建议您挑战)?
  • 你是完全正确的,我认为 Facebook API 的行为方式是我想要的(总是返回您请求的字段)但是当我仔细观察时,它实际上并没有返回一片空白。 (比较 graph.facebook.com/CocaCola?fields=foundedgraph.facebook.com/Fanta?fields=founded)。我可能会选择强类型 DTO 解决方案。
【解决方案2】:

考虑使用DynamicDictionary(参见System.Dynamic.DynamicObject 类文档中的“示例”部分),其中DynamicDictionary 派生自DynamicObject 类,能够在运行时获取/设置属性。

它使用内部字典来存储属性及其值,因此您最终不会得到很多未使用的属性,并且访问时间应该没问题。用法很简单

    // Creating a dynamic dictionary.
    dynamic person = new DynamicDictionary();

    // Adding new dynamic properties. 
    // The TrySetMember method is called.
    person.FirstName = "Ellen";
    person.LastName = "Adams";

或者您可以直接使用ExpandoObject,但它有点重,因为除了属性之外,它还允许您在此处存储事件和委托实例。

使用 XML/JSON 的序列化/反序列化在这里应该不是问题。

【讨论】:

  • 看起来不错!我考虑过使用 ExpandoObjects,但我不确定性能。但如果使用任何动态技术,DynamicObject 似乎就是其中之一。
  • +1,但我认为应该可以通过创建具有类型安全属性的类“Person”来增强这一点,其中每个未使用的属性不会在内部消耗任何内存,但你不能使用任何禁止的属性。
  • @Andrei Taptunov:在任何地方都找不到DynamicDictionary 的文档,你确定它在.NET 中吗?您能否提供一个指向它的文档的链接?
  • @casperOne:来自DynamicObject 的文档——只是其中一个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 2018-02-21
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多