每个层次表和复合主键

时间:2015-02-03 22:07:49

标签: c# entity-framework entity-framework-6 composite-primary-key table-per-hierarchy

我在遗留数据库中有两个表(我无法修改),数据如下:

two legacy tables

Table1具有复合主键(Code,Abbrev),但Abbrev也用作鉴别器(见下文)。 Table2有两个外键列(CodeA,CodeB),它们都引用Table1中的相同字段代码。 Table1.Code字段中有重复项。

我想在Entity框架6中使用table-per-hierarchy方法。因此,我创建了以下模型类:

[Table("Table1")]
public class MyBaseClass
{
    [Key]
    public string Code { get; set; }
}

public class MyBaseClassA : MyBaseClass
{
}

public class MyBaseClassB: MyBaseClass
{
}

[Table("Table2")]
public class SubClass
{
    [Key]
    public int Id { get; set; }

    [Required]
    [ForeignKey("MyBaseClassA")]
    public string CodeA { get; set; }

    public virtual MyBaseClassA ClassA { get; set; }

    [Required]
    [ForeignKey("MyBaseClassB")]
    public string CodeA { get; set; }

    public virtual MyBaseClassB ClassB { get; set; }

}

我在DataContext:DbContext类中定义了table-per-hierarchy,如下所示:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyBaseClass>().Map<MyBaseClassA>(m => m.Requires("Abbrev").HasValue("A"))
            .Map<MyBaseClassB>(m => m.Requires("Abbrev").HasValue("B"));
    }

问题是当我想使用这样的映射时 - 我不能使用鉴别器字段(Table1.Abbrev)作为MyBaseClass中复合键的一部分 - 我收到以下错误:

  

EntitySet'DataContext.MyBaseClass'中的所有对象必须具有唯一的主键。但是,“MyBaseClassA”类型的实例和“MyBaseClassB”类型的实例都具有相同的主键值,“EntitySet = MyBaseClass; Code = 1”。

是否可以使用Entity framework 6(或更新版本)映射上面的模型?

2 个答案:

答案 0 :(得分:1)

我担心实体框架无法做到这一点。

首先,您必须映射Table1的完整密钥,因为EF只能通过Table1识别Code个对象。并且不支持作为复合主键一部分的鉴别器。

因此您无法预设Table1子类型。现在,如果这就是全部,您可以选择不使用继承。但是Table2才是真正的阻尼者。 EF需要外键才能引用完整主键。因此,由于Table1应该有一个复合键,Table2两个foreigns键也应该看起来像{ Code, Abbrev }。好吧,Abbrev中甚至没有一个Table2字段。

你唯一能做的就是按原样映射Table1(没有继承),并且Table2之间没有任何关联。您必须手动编写连接(排序)以在一个查询中从数据库中获取相关记录。

例如,要获得Table2 Table1作为A

from t1 in context.Table1s
join t2 in context.Table2s on t1.Code equals t2.CodeA
where t1.Abbrev == "A"
select new { A = t1, t2 }

或者Table2同时Table1ATable1B

from t2 in context.Table2s
select new 
{
    t2,
    A = (from t1 in context.Table1s 
         where t1.Code == t2.CodeA && t1.Abbrev == "A")
        .FirstOrDefault(),
    B = (from t1 in context.Table1s 
         where t1.Code == t2.CodeB && t1.Abbrev == "B")
        .FirstOrDefault(),
}

答案 1 :(得分:0)

创建一个以“Abbrev”列为主键的新表。 (此表每个示例只有两行,“Abbrev”列值为“A”和“B”。)然后在此新表和现有Table1之间定义外键关系。在代码中,通过附加“Abbrev”列作为现有主键定义的一部分来更新Table1的MyBaseClass。

这应解决MyBaseClass生成的“必须具有唯一主键”错误。