Избежание «введения ограничения FOREIGN KEY может привести к циклам или нескольким каскадным путям» - PullRequest
0 голосов
/ 06 июля 2018

Я воспроизвел простой пример проблемы, возникшей у меня с 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; }
}

Когда я пытаюсь запустить программу, она выдает исключение:

'Введение ограничения FOREIGN KEY' FK_dbo.WorkOrders_dbo.Projects_ProjectId 'в таблицу' WorkOrders 'может вызвать циклы или несколько каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY.

Тогда я пошел другим путем. Я попробовал DB-первый подход с 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; }
}

Таким образом, код практически идентичен, за исключением SuppressMesages и конструкторов в классах WorkOrder и User. Второй подход работает.

Я хотел бы знать, в чем разница? Также контекстный класс идентичен моему. Где или как определяются эти ограничения FK или настройки каскадного удаления?

1 Ответ

0 голосов
/ 06 июля 2018

К сожалению, поведение кода EF по умолчанию в первую очередь заключается в создании FK при каскаде удаления. Поэтому при определении отношений вам нужно просто изменить этот параметр:

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

Также в modelBuilder.Conventions может быть соглашение для этого, если вы хотите просто изменить поведение для всех FK.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...