【问题标题】:Entity Framework 7: Identifying relationships实体框架 7:识别关系
【发布时间】:2016-07-01 02:07:22
【问题描述】:

在以前的 EF 版本中,我可以使用以下代码来实现识别关系:

public class Child
{
    [Key, Column(Order = 1)]
    public virtual int Id { get; set; }

    [Key, Column(Order = 2)]
    public virtual int ParentId { get; set; }
    public virtual Parent Parent { get; set; }
}

需要像这样轻松地从集合中删除一个孩子:

var parent = _context.Parents.First();
var child = parent.Children.First();

parent.Children.Remove(child);

_context.SaveChanges();

http://www.kianryan.co.uk/2013/03/orphaned-child/(方法#2)中描述了这种方法。

但在 EF7 中,此代码在创建迁移时会引发异常:

执行解析操作时引发异常。见 InnerException 了解详细信息。 ---> 实体类型“子”具有复合 使用数据注释定义的主键。设置复合主要 关键,使用流利的API。

我还尝试在以下代码中使用 How to define nested Identifying Relationships Entity Framework code first 中描述的 FluentAPI:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Parent>()
            .HasMany(p => p.Children)
            .WithOne(c => c.Parent);

        modelBuilder.Entity<Child>()
            .HasKey(c => new {c.Id, c.ParentId});

        base.OnModelCreating(modelBuilder);
    }

这种方法允许成功生成迁移,但是当我尝试从Children 集合中删除一个孩子时,我得到了以下异常:

System.InvalidOperationException:实体类型之间的关联 'Parent' 和 'Child' 已被切断,但其外键 关系不能设置为空。如果依赖实体应该是 删除,然后设置关系以使用级联删除。

但我不想使用级联删除,我想使用识别关系!

请帮助我理解我做错了什么。谢谢!

【问题讨论】:

  • 您想彻底删除孩子吗?或者您只想删除父子关系?
  • @MihailStancescu,是的,我想删除关系和孩子。
  • 您应该按照错误消息的说明配置级联删除。或者您必须手动删除您一开始不想要的孩子。
  • @MihailStancescu 我试过了,效果很好。看来我已经了解它的工作原理了...非常感谢!

标签: c# entity-framework entity-framework-core ef-fluent-api


【解决方案1】:

在删除时使用级联,因为这是它的用途:

modelBuilder.Entity<Parent>()
    .HasMany(p => p.Children)
    .WithOne(c => c.Parent);
    .WillCascadeOnDelete(true);

https://msdn.microsoft.com/en-gb/data/jj591620.aspx

【讨论】:

  • 您不必为此打开级联删除。级联删除用于在 删除关系的父级时删除子级,而不是在从集合中删除子级时删除子级 - 这就是设置标识关系的目的(即使用行 id 和外键的复合主键),这就是它在 EF 6 中的工作方式。也许 EF 7 中的情况发生了变化,但如果是这样,这仍然不是一个好主意,因为它并不总是可以打开如果创建循环事件链,则级联删除。
【解决方案2】:

万一有人看到这个错误,让我告诉你我是如何解决我的:

当您进行更新时,在 EF 上您需要首先查询数据库并获取数据模型,然后将您的更改映射到域层模型(基本上是将字段复制到数据上),最后调用 DBContext 更新方法,然后保存更改。

我的问题是我的模型(不是数据模型,域模型)也有子对象。

下面是数据层模型(例如):

public class Parent
{
   public int ChildId {get; set; }

   [ForeignKey("ChildId")]
   public virtual Child Child { get; set; }
}

领域层模型应该是这样的:

public class Parent
    {
        public int ChildId { get; set; }
        //public Child Child { get; set; }  // this caused the error, keep reading if you want to know more.
    }

当我看到错误时,我一直在使用 Autofac 的运行时映射器将域层模型的属性映射到数据层模型上。但是领域层模型中的child为null,所以会导致数据层为null,导致报错:

“实体类型 'Parent' 和 'Child' 之间的关联已被切断,但此关系的外键不能设置为 null。如果要删除依赖实体,则将关系设置为使用级联删除。”


顺便说一下,在db上下文类中,我定义了以下关系:

modelBuilder.Entity<Parent>()
   .HasOne(a => a.Child)
   .WithMany()
   .HasForeignKey(p => p.ChildId)
   .OnDelete(DeleteBehavior.Restrict);

它正在工作。

【讨论】:

  • 如果父级被删除,这确实会创建孤儿,但以防万一您出于某种原因想要这种行为,这就是如何做到的。
猜你喜欢
  • 1970-01-01
  • 2016-03-09
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多