C#实体框架 - 多个外键

时间:2017-06-07 09:42:05

标签: c# sql entity-framework

我有一个Entity Framework 6代码的问题,它首先在我的类中创建多个外键时应该只创建一个。考虑我有2个班级 -

public class Work
{
    public Work()
    {
        Document1 = new Collection<Document>();
        Document2 = new Collection<Document>();
        Document3 = new Collection<Document>();
    }
    [Key]
    public int WorkId { get; set; }
    public virtual ICollection<Document> Document1 { get; set; }
    public virtual ICollection<Document> Document2 { get; set; }
    public virtual ICollection<Document> Document3 { get; set; }
}

public class Document
{
    public int? WorkId { get; set; }
    [ForeignKey("WorkId")]
    public Work Work { get; set; }
}

现在,当我首先运行代码 update-database 命令时,在我的文档表中,它为Work表创建3个不同的外键 WorkId Work_Id1 Work_Id2 ,这应该只是一个外键而不是3.我知道应该有一个简单的注释来修复这个或我需要添加的流畅映射?

2 个答案:

答案 0 :(得分:1)

您的Work类有三个Document集合,因此Document类需要三个键来表示它附加的位置。如果我有一个Document的{​​{1}}为4的实例,那么WorkId的实例上是否存在该ID?它属于WorkDocument1还是Document2?只有一个键,就无法确定这一点。实体框架知道这一点,并创建了三个解决问题的键。

答案 1 :(得分:0)

显然,Work可能包含零个或多个Document1,零个或多个Document2以及零个或多个Document3。所有这些文件都是Document。

每个文档只属于一个Work,其中包含Document1Document2Document3。问题是当你使用你的类时,它不知道它是哪种Document类型。

最具数据库友好性和灵活性的解决方案是为每个文档提供一个属性,告诉它是哪种类型的文档,并将所有文档放在一个表中:

public enum DocumentType
{
    Document1,
    Document2,
    Document3,
};

public class Work
{
    public int WorkId { get; set; }
    public virtual ICollection<Document> Document { get; set; }
}

public class Document
{
    public int DocumentId {get; set;} // primary key
    public DocumentType DocumentType {get; set;}

    public int WorkId { get; set; }
    public Work Work { get; set; }
}
public MyDbContext : DbContext
{
    public DbSet<Work> Works {get; set;}
    public DbSet<Document> Documents {get; set;}
}

结果是一个包含文档的表。列WorkId将告诉您文档属于哪个工作。 Column DocumentType将告诉您它是Document1,Document2还是Document3。

这样,无需更改数据库即可轻松添加新的DocumentType。如果要快速搜索某种类型的所有文档,请考虑使用键(Id,DocumentType)创建额外的索引

如果你真的想要三个不同的表,例如因为将来Document1与Document2不再相似,你将不得不创建三个派生自Document的类,并为这些类创建三个DbSet

public class Document1 : Document
{
   public int WorkId {get; set;}
   public virtual Work Work {get; set;}
}
public MyDbContext : DbContext
{
    public DbSet<Work> Works {get; set;}
    public DbSet<Document1> Document1s {get; set;}
    public DbSet<Document2> Document2s {get; set;}
    public DbSet<Document3> Document3s {get; set;}
}

考虑使用Table-per-concrete-class。通过这种方式,您将获得一个包含Document1的表,一个包含Document2的表和一个用于Document3的表