繁体   English   中英

循环依赖删除(EF核心)

[英]Circular dependency on delete (EF core)

我的数据库中有两个相互引用的类,如下例所示。

Parent可以有任意数量的Child对象,我设置了一个外键约束让Child.ParentID引用Parent.ID 为关系设置DeleteBehavior.Cascade可确保在删除Parent时也删除所有Child对象。

问题是我还需要引用Parent class 中的一个Child对象,在下面的示例中称为PreferredChild 如果我设置DeleteBehavior.SetNull ,我期待在Parent.PreferredChildIdChild.ID之间创建约束会起作用,但实际发生的是,当我删除Parent object 时,如果设置了PreferredChildID ,我会得到这个异常:

System.InvalidOperationException:'无法保存更改,因为在要保存的数据中检测到循环依赖:'Parent [Deleted] PreferredChild PreferredParent {'PreferredChildID'} <- Child [Deleted] Parent Children {'ParentID'} <- Parent [已删除]'。

有没有办法 model 这样我就可以在不先取消设置PreferredChildID的情况下删除Parent object ?

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

public class Parent {
    public int? ID { get; set; }
    public int? PreferredChildID { get; set; }

    public virtual Child PreferredChild { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

public class Child {
    public int? ID { get; set; }
    public int? ParentID { get; set; }

    public virtual Parent Parent { get; set; }
    public virtual Parent PreferringParent { get; set; }
}

public class TestContext : DbContext {
    public DbSet<Parent> Parents { get; set; }
    public DbSet<Child> Children { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder options) {
        options.UseSqlite("Data Source=test.db");
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        // I would like to configure the model so that when a Parent is deleted, 
        // all Children are deleted. Using SetNull on PreferredChildID to avoid object
        // being deleted twice
        modelBuilder
            .Entity<Child>()
            .HasOne(c => c.PreferringParent)
            .WithOne(p => p.PreferredChild)
            .HasForeignKey<Parent>(p => p.PreferredChildID)
            .OnDelete(DeleteBehavior.SetNull);
        modelBuilder
            .Entity<Child>()
            .HasOne(c => c.Parent)
            .WithMany(p => p.Children)
            .HasForeignKey(c => c.ParentID)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

class Program {
    static void Main(string[] args) {
        using (var context = new TestContext()) {
            var parent = new Parent();
            context.Parents.Add(parent);
            context.SaveChanges();
            var child1 = new Child { ParentID = parent.ID };
            var child2 = new Child { ParentID = parent.ID };
            context.Children.AddRange(child1, child2);
            context.SaveChanges();
            parent.PreferredChildID = child2.ID;
            context.SaveChanges();
            // This explodes
            context.Parents.Remove(parent);
            context.SaveChanges();
        }

    }
}

为什么不只做以下事情?

 public class Parent { public int? ID { get; set; } public int? LastChildID => LastChild?.ID; public virtual Child LastChild => Children?.LastOrDefault(); public virtual ICollection<Child> Children { get; set; } }

编辑:在 OP 编辑了他的问题之后,他想要什么就更清楚了。

我建议像这样添加第三个表

CREATE TABLE [dbo].[PreferredChilds] (
    [ParentId]     INT          NOT NULL,
    [PreferredChild] INT    NOT NULL,
    PRIMARY KEY CLUSTERED ([ParentId] ASC, [PreferredChild] ASC),
    FOREIGN KEY ([ParentId]) REFERENCES [dbo].[Parents] ([Id]),
    FOREIGN KEY ([PreferredChild]) REFERENCES [dbo].[Children] ([Id])
);

这样你就不会对循环依赖有任何问题。 如果删除父项,则preferredchildschildren表中的条目也将被删除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM