c# - Entity Framework 6 代码优先 : what is the best implementation for a baseobject with 10 childobjects

标签 c# entity-framework entity-framework-6

我们首先有一个包含 10 个子对象和 EF6 代码的基础对象。

在这 10 个子对象中,5 个只有少数(额外)属性,5 个具有多个属性(5 到 20 个)。 我们将其实现为每个类型一个表,因此我们有一个基本表和每个 child 1 个表(总共 10 个)。

但是,这会在各处创建带有 select caseunions 的巨大选择查询,这也需要 EF 6 秒来生成(第一次)。

我读到了这个问题,同样的问题也存在于每个具体类型场景中。

所以我们剩下的是每个层次结构的表,但这会创建一个包含大量属性的表,这听起来也不太好。

是否有其他解决方案?

我考虑过当我想从所有子对象/记录中获取所有项目时可以跳过继承并创建一个联合 View 。

还有其他想法吗?

最佳答案

另一种解决方案是实现某种 CQRS pattern您有单独的数据库用于写入(命令)和读取(查询)。您甚至可以对读取数据库中的数据进行反规范化,因此速度非常快。

假设您至少需要一个具有参照完整性的规范化模型,我认为您的决定实际上取决于每个层次结构的表和每个类型的表。 TPH 是 reported by Alex James from the EF team最近on Microsoft's Data Development site以获得更好的性能。

TPT 的优点以及为什么它们不如性能重要:

更大的灵 active ,这意味着能够在不影响任何现有表的情况下添加类型。不必太担心,因为 EF 迁移使得生成所需的 SQL 来更新现有数据库而不影响数据变得微不足道。

由于可空字段较少而进行的数据库验证。不是一个大问题,因为 EF 根据应用程序模型验证数据。如果数据是通过其他方式添加的,那么运行后台脚本来验证数据并不难。此外,当涉及到主键时,TPT 和 TPC 实际上在验证方面更差,因为两个子类表可能包含相同的主键。您将面临通过其他方式进行验证的问题。

由于不需要存储所有空字段,因此减少了存储空间。这只是一个非常微不足道的问题,尤其是当 DBMS 具有处理“稀疏”列的良好策略时。

设计和直觉。拥有一个非常大的表确实感觉有点不对劲,但这可能是因为大多数数据库设计者都花了很多时间规范化数据和绘制 ERD。拥有一张大表似乎违背了数据库设计的基本原则。这可能是 TPH 的最大障碍。 See this article for a particularly impassioned argument .

该文章将反对 TPH 的核心论点总结为:

It's not normalized even in a trivial sense, it makes it impossible to enforce integrity on the data, and what's most "awesome:" it is virtually guaranteed to perform badly at a large scale for any non-trivial set of data.

这些大多是错误的。上面提到了性能和完整性,TPH 并不一定意味着非规范化。只有许多(可为空的)外键列是自引用的。因此,我们可以像使用 TPH 一样继续设计和规范化数据。在当前的数据库中,我在子类型之间有很多关系,并且创建了一个 ERD,就好像它是一个 TPT 继承结构一样。这实际上反射(reflect)了代码优先 Entity Framework 中的实现。例如,这是我的 Expenditure 类,它继承自 Relationship,而 Relationship 继承自 Content:

public class Expenditure : Relationship
{
    /// <summary>
    /// Inherits from Content: Id, Handle, Description, Parent (is context of expenditure and usually 
    /// a Project)
    /// Inherits from Relationship: Source (the Principal), SourceId, Target (the Supplier), TargetId, 
    /// 
    /// </summary>
    [Required, InverseProperty("Expenditures"), ForeignKey("ProductId")]
    public Product Product { get; set; }
    public Guid ProductId { get; set; }

    public string Unit { get; set; }
    public double Qty { get; set; }
    public string Currency { get; set; }
    public double TotalCost { get; set; }        

}

InversePropertyAttributeForeignKeyAttribute 为 EF 提供了在单个数据库中进行所需自联接所需的信息。

Product 类型也映射到同一个表(也继承自 Content)。每个 Product 在表中都有自己的行,包含 Expenditures 的行将在 ProductId 列中包含数据,对于包含所有其他类型的行,该列为空。所以数据是规范化的,只是放在一个表中。

首先使用 EF 代码的美妙之处在于,无论使用 TPH 还是 TPT,我们都以完全相同的方式设计数据库并以(几乎)完全相同的方式实现它。要将实现从 TPH 更改为 TPT,我们只需向每个子类添加注释,将它们映射到新表。所以,对您来说,好消息是您选择哪一个并不重要。就构建它,生成一堆测试数据,测试它,改变策略,再测试它。我想您会发现 TPH 是赢家。

关于c# - Entity Framework 6 代码优先 : what is the best implementation for a baseobject with 10 childobjects,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24449231/

相关文章:

c# - 压缩代码 : SetupSequence returning different values on successive calls

c# - 在 Net Core 中使用 Microsoft Graph Api 将用户添加为组成员

c# - 有条件地检索列表成员的语法

entity-framework - EF6 执行长时间运行的存储过程出现超时错误

c# - EF Code First From DB 不为所有表创建实体

c# - Identity Owin 是否需要延迟加载?

c# - MVVM 中 Model 和 ViewModel 的澄清和命名约定

c# - Linq to Entities - 查询以检查输入中 "n"个字符的匹配

c# - 使用数据库中的“选定”成员对组成员资格进行建模

entity-framework - Entity Framework 6 中的多异步?