【问题标题】:Entity Framework 5 Code First Self-Referencing RelationshipEntity Framework 5 Code First 自引用关系
【发布时间】:2013-09-22 07:33:41
【问题描述】:

如何在 Entity Framework 5 中映射以下关系?

public class Item {
  public int Id { get; set; }
  public int? ParentItemId { get; set; }
  public string Value { get; set; }

  public Item ParentItem { get; set; }
  public List<Item> ChildItems { get; set; }
}

我试过了:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
  base.OnModelCreating(modelBuilder);

  modelBuilder.Entity<Item>()
              .HasOptional(i => i.ParentItem)
              .WithMany(i => i.ChildItems)
              .HasForeignKey(i => i.ParentItemId);
}

还有这个:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
  base.OnModelCreating(modelBuilder);

  modelBuilder.Entity<Item>()
              .HasMany(i => i.ChildItems)
              .WithOptional(i => i.ParentItem)
              .HasForeignKey(i => i.ParentItemId);
}

两者都会导致此错误:

引用约束的Dependent Role中所有属性的类型必须与Principal Role中对应的属性类型相同。

如果我从数据库优先映射开始,生成的实体如下所示:

public partial class Item
{
    public Item()
    {
        this.ChildItems = new HashSet<Item>();
    }

    public int Id { get; set; }
    public Nullable<int> ParentItemId { get; set; }
    public string Value { get; set; }

    public virtual ICollection<Item> ChildItems { get; set; }
    public virtual Item ParentItem { get; set; }
}

我知道如果我从 db-first 开始这将起作用,我只需要知道如何在 code-first 中定义关系。

【问题讨论】:

  • Id 是关键属性吗?或者您是否有到另一个属性的键映射(使用 Fluent API?),例如到 Value
  • Id是Item的主键属性。
  • 从属角色中所有属性的类型”表示FK属性的类型,即ParentItemId,类型为int?。 “Principal Role 中对应的属性类型”是指Id 类型为int 的PK 属性类型。它们是相同的(可空性无关紧要)。但是,例外说,它们不是。例如,如果您有一个用于 PK 的 long(或任何其他类型)和一个用于 FK 的 int?,则会发生异常。比较奇怪……
  • 我已经复制了您发布的代码并运行它,它在我的系统上运行没有错误。我可以创建和读取项目,没有抛出异常。我正在使用 VS2013 RC 和 EF 6
  • @Slauma 这就是问题所在。我在这里发布了问题的简化表示(因为真实实体很大),但 Item 的主键实际上被标记为 long。感谢您指出了这一点。请发表回复,我会将其标记为答案。

标签: c# entity-framework foreign-keys entity-framework-5


【解决方案1】:

首先在代码中更改您的实体类,如下所示:

   public class Item 
   {
      public Item()
      {
            this.ChildItems = new HashSet<Item>();
      }

      public int Id { get; set; }
      public Nullable<int> ParentItemId { get; set; }
      public string Value { get; set; }

      public virtual Item ParentItem { get; set; }
      public virtual ICollection<Item> ChildItems { get; set; }
  }

将以下代码写入您的上下文文件:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Item>()
                    .HasOptional(i => i.ParentItem)
                    .WithMany(i => i.ChildItems)
                    .HasForeignKey(i => i.ParentItemId);
    }

认为这应该可行。

【讨论】:

  • 感谢您抽出宝贵时间回答。尝试这种方式时,我仍然得到相同的错误:引用约束的依赖角色中所有属性的类型必须与主体角色中的相应属性类型相同。
【解决方案2】:

为什么不试试这个:

 public class Item 
   {
      public Item()
      {
            ChildItems = new HashSet<Item>();
      }

      public int Id { get; set; }
      public int? ParentItemId { get; set; }
      public string Value { get; set; }

      public virtual Item ParentItem { get; set; }
      public virtual ICollection<Item> ChildItems { get; set; }
  }

在你的 DataContex 类中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Item>()
                    .HasOptional(i => i.ParentItem)
                    .WithMany()
                    .HasForeignKey(i => i.ParentItemId);
    }

希望这项工作。

这里也有一篇好文章: 如何在 Code First 中配置自引用实体 http://blogs.microsoft.co.il/gilf/2011/06/03/how-to-configure-a-self-referencing-entity-in-code-first/

【讨论】:

    【解决方案3】:

    异常的含义如下:

    • 依赖角色中所有属性的类型”是 FK 属性的类型,即 ParentItemId 并且在您的模型中具有类型 int?
    • Principal Role 中的相应属性类型”是 PK 属性的类型,它是 Id,在您的模型中具有类型 int

    它们是相同的(可空性无关紧要)。但是,例外情况表明,它们不是。

    该异常通常只会在类型不匹配时发生,例如,如果您有一个用于 PK 的 long(或任何其他类型)和一个用于 FK 的 int?

    【讨论】:

      【解决方案4】:

      尝试使用 mapKey 的方式而不是使用 HasForeignKey。喜欢

      modelBuilder.Entity<Course>()
          .HasRequired(c => c.Department)
          .WithMany(t => t.Courses)
          .Map(m => m.MapKey("ChangedDepartmentID"));
      

      【讨论】:

      • 感谢您花时间回答。以这种方式尝试时,我收到以下错误:类型中的每个属性名称必须是唯一的。已定义属性名称“ParentItemId”。
      • 在上述多对一映射之前添加对 ParentItemId 属性的忽略.. modelBuilder.Entity().Ignore(it => it.ParentItemId );
      猜你喜欢
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      相关资源
      最近更新 更多