【问题标题】:C# Entity Framework - Multiple Foreign KeysC# 实体框架 - 多个外键
【发布时间】:2017-06-07 18:25:24
【问题描述】:

我有一个问题,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 个不同的外键 WorkIdWork_Id1Work_Id2,这应该只是一个外键而不是 3。我知道应该有一个简单的注释来解决这个问题,或者我需要添加一个流畅的映射?

【问题讨论】:

  • Work 通过三个属性(集合)Document1、Document2 和 Document3 连接到 Document。这就是它创建三个外键的原因。如果您只想指定 1 个外键,其他两个将如何连接到 Document 实体。

标签: c# sql entity-framework


【解决方案1】:

您的Work 类具有三个Document 集合,因此Document 类需要三个键来表示它的附加位置。如果我有一个Document 的实例,其WorkId 为4,那么在具有该ID 的Work 实例上存在哪里?它属于Document1Document2 还是Document3?只有一把钥匙,没有办法确定这一点。 Entity Framework 知道这一点,并创建了三个键来解决问题。

【讨论】:

    【解决方案2】:

    显然Work 可能有零个或多个Document1、零个或多个Document2 和零个或多个Document3。所有这些文档都是 Document 类型。

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

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

    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 列将告诉您文档属于哪个 Work。列 DocumentType 将告诉您它是 Document1、Document2 还是 Document3。

    这样可以很容易地添加新的 DocumentTypes 而无需更改数据库。如果您想快速搜索特定类型的所有文档,请考虑使用键 (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 的表格

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多