使用实体框架的动态\用户可扩展实体

时间:2013-02-22 08:19:28

标签: entity-framework design-patterns dynamic-data

我将实体框架用于一个相当简单的问题跟踪应用程序。 我想通过添加其他属性(例如:

)为用户提供扩展“问题”实体的功能
  • 数字字段
  • 文本字段(简单或富文本)
  • 不同的列表(多个\单选)
  • 布尔属性

我想到了完成任务的两种方法:

可扩展数据库方法

这种做法只是一个想法,我不知道如何使用实体框架实现,所以我非常希望得到你的帮助。 这是基本概念:

  1. 创建一个名为IssueExtendedFields的表,该表将包含描述其类型和名称以及其他属性的每个字段的记录。
  2. 创建另一个名为IssueFieldOptions的表,该表将包含每个“列表类型字段”的选项列表
  3. 最后一个表格使得IssueExtendedFieldValues占用了一个列,该列包含用户创建的每个自定义字段的特定命名约定以及每个问题的外键..
  4. 现在我只是不知道如何实现第3步,因为使用实体框架并且存在从表中生成的EF实体对象(DB优先),因此每个新列理论上都必须重新映射和重新编译DAL项目。

    你还有其他建议吗?

    字典方法

    这种方法我知道如何实现

    1. 创建一个名为IssueExtendedFields的表,该表将包含描述其类型和名称以及其他属性的每个字段的记录。
    2. 创建另一个名为IssueFieldOptions的表,该表将包含每个“列表类型字段”的选项列表
    3. 最后一张名为IssueExtendedFieldValues的表格将为每个输入系统的“Field - Value”对保留一条记录
    4. 但它有许多缺点(如果你看到如何过来请发布)。

      1. 用户添加的每个新属性只是另一条记录将每个实体存储的数据量乘以X,其中X是属性数量,我看到大量问题进入系统并创建一个单独的表格来保存每个问题的10个记录将生成需要大量内存的大量查询。
      2. 除了预见的内存问题,我还必须创建动态“Pivot”,如报表和视图,以允许用户再次生成报表自定义属性,当您处理大量数据时,“Pivot”查询将采取更多的时间。

2 个答案:

答案 0 :(得分:3)

我知道这个问题很老了,但是没有什么能阻止你在运行时使用你特定时刻的数据库模式来构建你的EF数据模型。由于您的大多数数据模型都是静态的,因此增加的复杂性本地化为在运行时可以更改的实体:

  1. 在运行时向数据库添加列时,还需要向相应类型添加属性。这意味着您的类型是在运行时构造的。您可能会在运行时使用其他属性创建派生的类型(或实现某些接口),以便您的编译时代码具有合理的类型来处理。这可以使用Reflection.Emit完成。

  2. 每当架构发生变化时,您都需要在运行时动态构建EF映射。您可以使用EF Code First执行此操作。如果您的映射符合正常的EF Code First约定,那么除了确保将运行时类型添加到映射之外,您无需执行此操作。否则,您必须实现在运行时为其他属性确定和配置必要映射的代码。

  3. 任何利用其他属性的查询都需要在运行时动态构建。这意味着要在LINQ查询中使用building member access expressions。同样,访问仅在运行时已知的其他属性的值需要reflection

  4. 你是正确的,要警惕你的第二种方法,这种方法更广为人知的是Entity-Attribute-Value (EAV) data modeling。这种方法有许多缺点,其中最重要的是增加了连接/查询复杂性和缺少外键支持。但是,由于EAV模型是在编译时声明的,因此可以说更容易实现。

    或者,您可以考虑专门为具有灵活架构的实体使用其他数据存储,例如document databases

答案 1 :(得分:0)

  
    

因此理论上每个新专栏都必须重新映射并重新编译DAL项目。

  

你回答了自己的问题:) EF使用固定数据库模式,因此无论如何第一个选项都不是一个选项。