避免“引入FOREIGN KEY约束可能会导致循环或多个级联路径”

时间:2018-07-06 10:02:08

标签: c# sql entity-framework

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

我想拥有三个表:

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进行数据库优先的方法。我首先在SQL Server Management Studio中创建了表和连接:

Diagram

然后,使用代码优先方法,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; }
}

因此,除了SuppressMesagesWorkOrder类中的User和构造函数以外,代码几乎完全相同。第二种方法可行。

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

1 个答案:

答案 0 :(得分:1)

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

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

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