【问题标题】:Specifying ON DELETE NO ACTION in Entity Framework 7? [duplicate]在实体框架 7 中指定 ON DELETE NO ACTION? [复制]
【发布时间】:2016-01-13 14:15:41
【问题描述】:

在 Entity Framework 7 中,当我尝试应用迁移时出现错误

在表“ChangeOrder”上引入 FOREIGN KEY 约束“FK_ChangeOrder_User_CreatedByID”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
无法创建约束。查看以前的错误。

我知道在旧版本的实体框架中,您可以通过添加来处理这个问题

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

到 DbContext 但在 EF7 中 modelBuilder 似乎没有 .Conventions 并且谷歌只返回旧的 EF 4 虽然 EF 6 结果。

如何在 Entity Framework 7 中指定 ON DELETE NO ACTION 约束?

编辑: 奥列格提供的答案显然会根据外键来做,但我想在全球范围内做,因为使用一行代码在全球范围内声明它会更容易,然后必须为数百个中的每一个指定代码我最终会拥有的关系。

编辑 2:Oleg 的代码

public class ChangeOrder
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public Int16? ApprovedByID { get; set; }
    public Byte ApprovalStatusID { get; set; }
    public Int16 AssignedToID { get; set; }
    public Int16 CreatedByID { get; set; }
    public Byte CurrentStatusID { get; set; }
    public DateTime? DateApproved { get; set; }
    public DateTime? EndDate { get; set; }
    public Byte ImpactID { get; set; }
    public Byte PriorityID { get; set; }
    public DateTime? StartDate { get; set; }
    public Byte TypeID { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string ReasonForChange { get; set; }

    [ForeignKey("ApprovedByID")]
    public User ApprovedBy { get; set; }

    [ForeignKey("ApprovalStatusID")]
    public ChangeApprovalStatus ApprovalStatus { get; set; }

    [ForeignKey("AssignedToID")]
    public User AssignedTo { get; set; }

    [ForeignKey("CreatedByID")]
    public User CreatedBy { get; set; }

    [ForeignKey("ImpactID")]
    public ChangeImpact Impact { get; set; }

    [ForeignKey("PriorityID")]
    public ChangePriority Priority { get; set; }

    [ForeignKey("TypeID")]
    public ChangeType ChangeType { get; set; }

    [ForeignKey("CurrentStatusID")]
    public ChangeStatus CurrentStatus { get; set; }
}
public class JobSightDBContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        base.OnModelCreating(modelbuilder);
    }

    DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; }
    DbSet<ChangeImpact> ChangeImapct { get; set; }
    DbSet<ChangeOrder> ChangeOrders { get; set; }
    DbSet<ChangePriority> ChangePriorities { get; set; }
    DbSet<ChangeStatus> ChangeStatus { get; set; }
    DbSet<ChangeType> ChangeTypes { get; set; }
    DbSet<User> Users { get; set; }
}

【问题讨论】:

    标签: c# entity-framework-core


    【解决方案1】:

    在 GitHub 上进行挖掘,并与一位来自 MS 的非常有耐心的人一起工作后,当前的解决方案是将其添加到 DbContext

    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        foreach (var relationship in modelbuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
        {
            relationship.DeleteBehavior = DeleteBehavior.Restrict;
        }
    
        base.OnModelCreating(modelbuilder);
    }
    

    【讨论】:

    • 这救了我的命!!!!!!!我遇到了很多建模 FK 问题。谢谢一百万!!!!!!!!!!!!!!!!
    • DeleteBehavior但没有UpdateBehavior
    • 这在 EF Core 2.1 中不起作用 :(
    • 不适合我:“DbModelBuilder”不包含“模型”的定义..
    • 只是添加注释,如果没有看到 SelectMany(默认)使用 System.Linq 添加;
    【解决方案2】:

    建筑

    modelBuilder.Entity("myNamespace.Models.ChangeOrder", b =>
        {
            b.HasOne("myNamespace.Models.User")
                .WithMany()
                .HasForeignKey("CreatedByID")
                .OnDelete(DeleteBehavior.Cascade);
        });
    

    将意味着用REFERENCES [dbo].[User] ([CreatedByID]) ON DELETE CASCADE 创建FK_ChangeOrder_User_CreatedByID。它应该存在于迁移期间创建的YourContextModelSnapshot.cs 中的protected override void BuildModel(ModelBuilder modelBuilder) 中。我不确定我是否完全理解您的问题,但我认为您应该将此类构造添加到 XXXModelSnapshot.cs 或删除此处已经存在的不需要的构造。

    更新:我发现您在模型中遇到了问题。您在

    中有以下属性
    public Int16? ApprovedByID { get; set; }
    public Int16 AssignedToID { get; set; }
    public Int16 CreatedByID { get; set; }
    
    // navigation properties
    
    [ForeignKey("ApprovedByID")]
    public User ApprovedBy { get; set; }
    
    [ForeignKey("AssignedToID")]
    public User AssignedTo { get; set; }
    
    [ForeignKey("CreatedByID")]
    public User CreatedBy { get; set; }
    

    默认迁移尝试在所有属性上设置DeleteBehavior.Cascade

    您可以通过更改OnModelCreating 来覆盖该行为,这将为所有键设置DeleteBehavior.Restrict 行为,或者将DeleteBehavior.CascadeDeleteBehavior.SetNull 行为仅设置在一个键上。例如,下面的代码在CreatedByID 上使用DeleteBehavior.Cascade(在外键上创建ON DELETE CASCADE)和在其他外键上使用DeleteBehavior.Restrict(在外键上没有ON DELETE):

    public class JobSightDBContext : DbContext
    {
        protected override void OnModelCreating(ModelBuilder modelbuilder)
        {
            base.OnModelCreating(modelbuilder);
    
            modelbuilder.Entity(typeof (ChangeOrder))
                .HasOne(typeof (User), "ApprovedBy")
                .WithMany()
                .HasForeignKey("ApprovedByID")
                .OnDelete(DeleteBehavior.Restrict); // no ON DELETE
            modelbuilder.Entity(typeof (ChangeOrder))
                .HasOne(typeof (User), "AssignedTo")
                .WithMany()
                .HasForeignKey("AssignedToID")
                .OnDelete(DeleteBehavior.Restrict); // no ON DELETE
            modelbuilder.Entity(typeof (ChangeOrder))
                .HasOne(typeof (User), "CreatedBy")
                .WithMany()
                .HasForeignKey("CreatedByID")
                .OnDelete(DeleteBehavior.Cascade); // set ON DELETE CASCADE
        }
    
        DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; }
        DbSet<ChangeImpact> ChangeImapct { get; set; }
        DbSet<ChangeOrder> ChangeOrders { get; set; }
        DbSet<ChangePriority> ChangePriorities { get; set; }
        DbSet<ChangeStatus> ChangeStatus { get; set; }
        DbSet<ChangeType> ChangeTypes { get; set; }
        DbSet<User> Users { get; set; }
    }
    

    【讨论】:

    • 有没有办法在全球范围内做到这一点,或者我必须为我拥有的数百个关系中的每一个都这样做?这样做会为我创建很多额外的编码,我宁愿避免这样做。
    • @MatthewVerstraete:只有错误消息很难回答。我想您首先创建了一组具有许多数据符号的类,然后创建了从 DbContext 派生的 XXXContext,它们具有许多属性,例如 public DbSet&lt;User&gt; Users { get; set; }public DbSet&lt;ChangeOrder&gt; ChangeOrders { get; set; }。我想UserChangeOrder 中的一些定义会被 EF Migration 以错误的方式解释,但我猜不出它到底是什么。需要分析完整的模型才能找到原因。
    • 不确定您理解的问题。我正在寻找 modelBuilder.Conventions.Remove&lt;OneToManyCascadeDeleteConvention&gt;(); 的 EF7 版本,但我添加了 DBContext 和模型供您查看
    • @MatthewVerstraete:我想尽快通知您,我现在必须为我的客户做一些重要的事情。稍后(几个小时后)我会再回复您的问题。
    • @Olga 是的,EF7 的默认行为是设置 ON DELETE CASCADE 我想覆盖它并删除该行为,因此默认设置为 ON DELTE NO ACTION。在 EF6 中,这是使用 modelBuilder.Conventions.Remove&lt;OneToManyCascadeDeleteConvention&gt;(); 完成的。您向我展示的是如何为每个属性一一做。我需要知道的是如何将DeleteBehavior.Restrict 设置为 EF7 的默认行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 2013-08-01
    • 1970-01-01
    • 2021-05-29
    • 2023-01-24
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多