繁体   English   中英

EF6:在SQL Server中包括嵌套的TPH结构

[英]EF6: Include over nested TPH structure in SQL Server

大家好,2017年新年快乐,

我有以下表/对象结构。

[Table("Table1")]
public class Table1
{
    [Key]
    public long Table1Id { get; set; }

    public virtual ICollection<Table2> ItemsOfTable2 { get; set; }
}

[Table("Table2")]
public class Table2
{
    [Key]
    public long Table2Id { get; set; }

    public long Table1Id { get; set; }

    [ForeignKey("Table1Id")]
    public virtual Table1 Table1Object { get; set; }

    public virtual ICollection<Table3Base> ItemsOfTable3 { get; set; }

    [NotMapped]
    public virtual ICollection<Table3Red> RedItems
    {
        get { return this.ItemsOfTable3.OfType<Table3Red>().ToList(); }
    }

    [NotMapped]
    public virtual ICollection<Table3Blue> BlueItems
    {
        get { return this.ItemsOfTable3.OfType<Table3Blue>().ToList(); }
    }
}

[Table("Table3Base")]
public abstract class Table3Base
{
    [Key]
    public long Table3Id { get; set; }

    public long Table2Id { get; set; }

    [ForeignKey("Table2Id")]
    public virtual Table2 Table2Object { get; set; }
}

public class Table3Red : Table3Base
{
    public string SpecialPropertyForRed { get; set; }
}

public class Table3Blue : Table3Base
{
    public int SpecialPropertyForBlue { get; set; }

    public virtual ICollection<Table4> ItemsOfTable4 { get; set; }
}

[Table("Table4")]
public class Table4
{
    [Key]
    public long Table4Id { get; set; }

    public long Table3Id { get; set; }

    [ForeignKey("Table3Id")]
    public virtual Table3Blue Table3BlueObject { get; set; }
}

public class MyContext : DbContext
{
    public virtual IDbSet<Table1> Table1DbSet { get; set; }
    public virtual IDbSet<Table2> Table2DbSet { get; set; }
    public virtual IDbSet<Table3Red> Table3RedDbSet { get; set; }
    public virtual IDbSet<Table3Blue> Table3BlueDbSet { get; set; }
    public virtual IDbSet<Table4> Table4DbSet { get; set; }
}

因此,在此“树”的中间,有一个TPH结构(存储在数据库表“ Table3Base”中的Table3Base,Table3Red,Table3Blue类)。 而且我们只有用于Table3Red和Table3Blue的IDbSet,而没有用于Table3Base的IDbSet。 每个对象都有下一个表对象的集合导航属性。

Table3Blue类具有另一个Table4对象项的集合导航属性。

更多(但希望不相关)的信息:默认区分符映射到内部枚举:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

    // TPH: Map Standard-Discriminator to Enum
    modelBuilder.Entity<Table3Base>()
        .Map<Table3Red>(m => m.Requires("Typ").HasValue((int)Table3TypEnum.Red))
        .Map<Table3Blue>(m => m.Requires("Typ").HasValue((int)Table3TypEnum.Blue));
}

由于性能问题(一个记录一个一个地加载每个记录非常慢;延迟加载处于活动状态),我们希望通过以下方式从Table1到Table4读取此结构:

var table1Records = this.m_Context.Table1DbSet
    .Include(t => t.ItemsOfTable2)
    .Include(t => t.ItemsOfTable2.Select(t2 => t2.ItemsOfTable3))
    .Include(t => t.ItemsOfTable2.Select(t2 => t2.ItemsOfTable3.OfType<Table3Blue>().Select(t3 => t3.ItemsOfTable4)))
    .ToList();

第一个和第二个include似乎起作用,但是第三个include抛出Argument异常“ Include路径表达式必须引用在类型上定义的导航属性。对于引用导航属性,请使用虚线路径,对于集合导航属性,请使用Select运算符。参数名:路径”。

我究竟做错了什么? 如何在通往数据库的途中包含Table4-对象?

亲切的问候

这是我们的解决方法。 我怀疑这是最好的解决方案,因此更好的方法受到高度赞赏...

Table3Base将集合导航属性作为虚拟属性获取到Table4。

Table3Red(没有Table4-objects的对象)使用getter覆盖此属性,该getter返回Table4对象的空列表且没有setter。

因此,我们可以将Include向下层叠到Table4,而无需进行任何类型检查。 在我们的PTH数据库表“ Table3Base”中没有不必要的记录。 因此,除了Table3Red的笨拙定义(具有未使用的导航属性)之外,其他所有内容都很好。 :-(

顺便说一句:长路径包含包含该路径上的所有对象,因此不需要显式的“ .Include(A).Include(AB).Include(ABC)”; “ .Include(ABC)”将执行相同的操作。 为了清楚起见,代码示例中的迭代.include。

HTH,伴侣

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM