【问题标题】:Avoiding 'Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths'避免“引入 FOREIGN KEY 约束可能导致循环或多个级联路径”
【发布时间】:2018-12-14 21:56:41
【问题描述】:

我复制了一个关于实体框架问题的简单示例。

我想要三个表:

Users, Projects, WorkOrders

Users 包含所有其他表的用户信息(示例中只有两个)。 WorkOrders 有关于哪些User 必须处理此工单以及它属于哪个Project 的信息。

以下是课程:

public class User
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<WorkOrder> WorkOrders { get; set; }
    public virtual ICollection<Project> Projects { get; set; }
}

public class Project
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public int ManagerId { get; set; }
    public DateTime Start { get; set; }

    public virtual User Manager { get; set; }
    public virtual ICollection<WorkOrder> WorkOrders { get; set; }
}

public class WorkOrder
{
    [Key]
    public int Id { get; set; }
    public int Number { get; set; }
    public string Type { get; set; }
    public int AssigneeId { get; set; }
    public int ProjectId { get; set; }

    public virtual Project Project { get; set; }
    public virtual User Assignee { get; set; }
}

当我尝试运行程序时,它会抛出异常:

'在表'WorkOrders'上引入 FOREIGN KEY 约束'FK_dbo.WorkOrders_dbo.Projects_ProjectId'可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

然后我走了另一条路。我用 EF 尝试了 DB-first 方法。我首先在 SQL Server Management Studio 中创建了表和连接:

然后 EF 生成的模型看起来和我的几乎一样,都是代码优先的方法。

public partial class User
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public User()
    {
        this.Project = new HashSet<Project>();
        this.WorkOrder = new HashSet<WorkOrder>();
    }

    public int Id { get; set; }
    public string Name { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Project> Project { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<WorkOrder> WorkOrder { get; set; }
}

public partial class Project
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Project()
    {
        this.WorkOrder = new HashSet<WorkOrder>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public int ManagerId { get; set; }
    public System.DateTime Start { get; set; }

    public virtual User User { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<WorkOrder> WorkOrder { get; set; }
}

public partial class WorkOrder
{
    public int Id { get; set; }
    public int Number { get; set; }
    public string Type { get; set; }
    public int AssigneeId { get; set; }
    public int ProjectId { get; set; }

    public virtual Project Project { get; set; }
    public virtual User User { get; set; }
}

所以代码几乎相同,除了SuppressMesagesWorkOrderUser 类中的构造函数。第二种方法有效。

我想知道,有什么区别?上下文类也与我自己的相同。 FK 约束或级联删除设置在何处或如何定义?

【问题讨论】:

    标签: c# sql entity-framework


    【解决方案1】:

    不幸的是,EF 代码的默认行为是在删除级联时首先创建 FK。因此,在定义关系时,您只需更改此设置:

    //in context
    protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
        modelBuilder.Entity<Project>()
            .HasRequired<User>(s => s.User)
            .WithMany()
            .WillCascadeOnDelete(false);
    

    如果您只想更改所有 FK 的行为,modelBuilder.Conventions 中可能还有一个约定。

    【讨论】:

      猜你喜欢
      • 2011-05-08
      • 2013-10-22
      • 2019-10-20
      • 2018-08-08
      • 2017-04-26
      • 1970-01-01
      相关资源
      最近更新 更多