【问题标题】:What is the syntax for self referencing foreign keys in EF Code First?EF Code First 中自引用外键的语法是什么?
【发布时间】:2011-06-16 05:18:17
【问题描述】:

我正在尝试将外键从 SpouseId 引用到 Contact 表中的 Id。这样做的语法是什么?我似乎找不到一个例子。谢谢。

我有这样的课:

public class Contact
{
    public int Id {get;set;}
    public string Name {get;set;}
    public int? SpouseId {get;set;}
}

EDIT1 根据 Joel Cunningham 提供的 link 和 Morteza 的回答,我添加了一些额外的代码。

ContactMap.cs

public partial class ContactMap : EntityTypeConfiguration<Contact>
{
  public ContactMap()
     {
       this.ToTable("Contact");
       this.HasKey(c => c.Id);
       this.HasOptional(c => c.Spouse)
           .WithMany()
           .IsIndependent()
           .Map(m => m.MapKey(fk => fk.Id, "SpouseId"));
     }
}

MyObjectContext.cs

public class MyObjectContext : DbContext, IDbContext
{
  public DbSet<Contact> Contacts {get;set;}
  protected override void OnModelCreating(ModelBuilder modelBuilder)
     {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Configurations.Add(new ContactMap());
     }
}

注意:我还在 Contact 类中的 Spouse 属性中添加了“[ForeignKey("SpouseId")]”属性。不幸的是,我不断收到“序列包含多个匹配元素”。

EDIT2: Morteza 在下面的回答是正确的。总结一下:对于自引用外键,您可以将属性标记为“[ForeginKey("SpouseId")] 或使用下面的流畅 API 示例。我在某些 cmets 中报告的错误是由我的单元测试引起的。EF以正确的方式生成数据库。我找到了一个很好的link where Craig Stuntz 概述了为什么自动增量键和自引用外键会导致“无法确定相关操作的有效排序”错误。我相信这是我的问题是什么。希望这对某人有所帮助。

【问题讨论】:

  • 这看起来像我所追求的。您是否知道属性“[ForeignKey]”在哪个程序集中?我似乎也找不到。
  • System.ComponentModel.DataAnnotations

标签: entity-framework ef-code-first


【解决方案1】:
_ = builder.HasMany(e => e.Children)
            .WithOne(e => e.Parent)
            .HasForeignKey(e => e.ParentId);

以上代码对我有用

【讨论】:

    【解决方案2】:
    [Table("Move")]
    public class Move
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long ID { get; set; }
        public long? ParentID { get; set; }
    
        [InverseProperty("Children")]
        public virtual Move Parent { get; set; }
        public virtual ICollection<Move> Children { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      另外,导航属性Spouse 应该是虚拟的以避免不必要的 JOIN 查询:

       public virtual Contact Spouse { get; set; }
      

      【讨论】:

      • 你能解释一下为什么必须是虚拟的吗?
      • 虚拟不是必需,但可以通过为 Spouse 对象启用延迟加载来节省不必要的 JOIN 查询。见link。编辑了我的回复以澄清。
      • @ReflexiveCode 你是说没有virtualSpouse 会被加载?我认为您需要 Include 来热切地加载它。
      【解决方案4】:

      这样的事情会起作用:

      public class Contact
      {
          public int Id {get;set;}
          public string Name {get;set;}
          public int? SpouseId {get;set;}
      
          [ForeignKey("SpouseId")]
          public Contact Spouse {get;set;}
      }
      

      ForeignKeyAttribute 已被 CTP5 程序集添加到 System.ComponentModel.DataAnnotations

      更新一:CTP5 错误:

      由于 CTP5 中的错误,创建独立自引用关联会引发异常。解决方法是改用 外键关联(无论如何总是推荐)。

      更新二:使用 Fluent API 配置自引用关联:

      如果您愿意,也可以使用 fluent API 来实现:

      public class Contact
      {
          public int Id { get; set; }
          public string Name { get; set; }
          public int? SpouseId { get; set; }                
      
          public Contact Spouse { get; set; }
      }
      
      public class Ctp5Context : DbContext
      {
          public DbSet<Contact> Contacts { get; set; }
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              modelBuilder.Entity<Contact>()
                          .HasOptional(c => c.Spouse)
                          .WithMany()
                          .HasForeignKey(c => c.SpouseId);
          }
      }
      

      使用模型:

      using (var context = new Ctp5Context())
      {
          Contact contact = new Contact()
          {
              Name = "Morteza",
              Spouse = new Contact()
              {
                  Name = "Code-First"
              }
          };
          context.Contacts.Add(contact);
          context.SaveChanges();
      }
      

      【讨论】:

      • @Morteza。我不断收到“序列包含多个匹配元素”。我也使用了您在上面的链接答案中提供的映射语法。我知道这是必要的,因为没有它,EF 会抛出错误,抱怨不知道外键关系。
      • 您在 ContactMap 类中编写的流畅 API 代码都不是必需的。只有我展示的ForeignKeyAttribute 就足够了。同样,由于我在更新答案中所说的错误,在这种情况下您不能拥有独立协会。
      • 好的。我误解了你的回答。我认为您的回答是解决该错误的方法。我通常不喜欢在我的 POCO 中使用属性,所以我现在将根据我的需要创建一个映射表。下一个版本会修复这个错误并允许这种类型的映射吗?仅供参考,您对 SO 和其他地方的 CTP5 的帮助非常有帮助。谢谢。
      • 另一个注释。即使在取出 SpouseId 的流畅 API 代码后,我也无法让您的示例正常工作。我不断收到“无法确定相关操作的有效排序”。
      • 我更新了我的答案,以展示如何在不使用数据注释的情况下做到这一点。是的,EF 团队意识到了这个错误,并将确保在 RTM 中修复这个错误。顺便说一句,我无法重现您遇到的异常,您能否发布导致此“无法确定相关操作的有效排序”异常的代码?谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      相关资源
      最近更新 更多