2016-08-23 3 views
3

У меня есть 4 класса модели в моем проекте Asp.Net Mvc. Я сначала использую Entity Framework Code (Автоматическая миграция). Я, когда запускаю команду update-database, получаю следующую ошибку;Код элемента Entity Framework Сначала один для многих ошибок каскада

Представляя ограничение внешнего ключа «FK_dbo.Tickets_dbo.Users_CreatedUserId» на столе «» Билеты могут вызвать циклов или несколько путей каскада. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY. Не удалось создать ограничение или индекс. См. Предыдущие ошибки.

В чем проблема?

//Company Class 
public class Company 
{ 
    public int Id { get; set; } 

    [Required, StringLength(100)] 
    public string Title { get; set; } 

    public virtual ICollection<User> Users { get; set; } = new HashSet<User>(); 
} 

//User Class 
public class User 
{ 
    public int Id { get; set; } 

    [Required, StringLength(50)] 
    public string UserName { get; set; } 

    [Required, StringLength(100)] 
    public string FullName { get; set; } 

    public int CompanyId { get; set; } 
    public virtual Company Company { get; set; } 
} 

//Ticket Class 
public class Ticket 
{ 
    public int Id { get; set; } 

    [Required] 
    public DateTime CreationDate { get; set; } 

    [Required, StringLength(100)] 
    public string Title { get; set; } 

    public bool IsClosed { get; set; } 

    public int CreatedUserId { get; set; } 
    public virtual User CreatedUser { get; set; } 

    public virtual ICollection<TicketMessage> Messages { get; set; } = new HashSet<TicketMessage>(); 
} 

//TicketMessage Class 
public class TicketMessage 
{ 
    public int Id { get; set; } 

    public DateTime Date { get; set; } 

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

    public int UserId { get; set; } 
    public virtual User User { get; set; } 

    public int TicketId { get; set; } 
    public virtual Ticket Ticket { get; set; } 

} 
+0

Это потому, что в таблице 'Users' есть много« билетов », а также многие« TicketMessages », и одновременно« Ticket »имеет много« TicketMessages ». – Szer

+0

Да, это должно быть так. Потому что пользователи могут создавать билет и билет. –

+0

Но SQL-движок не знает, что делать, если вы удаляете один конкретный «Пользователь». Вы должны сделать так, как это буквально сказано: укажите, следует ли «ВКЛЮЧИТЬ УДАЛЕНИЕ НЕТ ДЕЙСТВИЯ» или сделать пользовательский «триггер удаления» – Szer

ответ

1

Если вы удалите запись в одной модели (родительской), она удалит все записи в дочерней модели, относящиеся к ней. В этом случае модель Users является родительской, у которой есть много билетов и TicketMessages, поэтому, когда вы удаляете удаление каскада пользователя, вы также удаляете всех пользователей Tickets и TicketMessages. Когда модель имеет свойство навигации, EF автоматически назначает внешний ключ. Внешние ключи создают отношения между моделями и означают, что вы не можете удалить запись в одной модели, когда запись в «дочерней» модели зависит от внешнего ключа, присутствующего в качестве первичного ключа в записи, которую вы пытаетесь удалить.

В вашей ситуации, о которой было сказано в комментарии, ваша модель пользователя имеет отношения друг к другу как с билетами, так и с TicketMessages, ваша модель Ticket имеет отношение один к большому с TicketMessages. Это означает, что удаление пользовательской записи удалит все TicketMessages и Tickets, связанные с этим UserID, за исключением того, что возможно (для системы), что TicketMessage с этим UserID также использует TickedID, который не удаляется каскадом из UserID , Следовательно, ошибка, потому что это нарушает отношения внешнего ключа.

Есть два решения:

1 - изменить дизайн, ваша модель TicketMessages уже имеет отношение с билетом, через ID Билет и, следовательно, имеет отношение с UserID, как Идентификатор_пользователь связан с ID Билетом в модели Ticket , Поэтому вы можете удалить отношения UserID из модели TicketMessage, это не требуется. Ваша проблема будет решена. Это действительно правильное решение в моем сознании, так как это ваш дизайн, который является проблемой.

2 - Если вы по какой-то причине я не могу воспринимать хотите сохранить эти отношения, вы можете отключить каскадное удаление в целом с помощью:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
    modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 
} 

двух линий удалить как один ко многим и многие ко многим каскаде соответственно. Вы можете удержать их или удалить их по своему усмотрению.

Вы также можете удалить особые отношения каскадного удаления, используя следующие:

modelBuilder.Entity<ParentEntity>() 
.HasMany(p => p.Children) 
.WithRequired() 
.HasForeignKey(c => c.ParentEntityId) 
.WillCascadeOnDelete(false); 

Я настоятельно рекомендую решение 1, удалить UserID из модели TicketMessages, ваши TicketMessages уже связаны с UserID через отношения между Модель TicketMessages и модель Ticket.

Редактировать - Мне пришло в голову, что вы можете установить связь между TicketMessages и User, чтобы указать, кто написал сообщение, когда это лицо не является тем же пользователем, который создал билет. Если это так, я все же предлагаю удалить связь с таблицей User и вместо этого использовать поле, в котором вы можете заполнить любую информацию пользователя, которую вы хотите связать с этим сообщением о билете, когда оно создано, например. Имя.Или, альтернативно, вы все равно можете иметь поле UserID, но без свойства навигации, удаляя отношения внешнего ключа. Затем информация пользователя может быть вызвана путем сопоставления этого UserID с одним в таблице User при получении информации.

1

Благодарим за ответ. Роб! Я решил эту проблему следующим кодом.

modelBuilder.Entity<User>() 
      .HasMany(e => e.TicketMessages) 
      .WithRequired(e => e.User) 
      .WillCascadeOnDelete(false); 
Смежные вопросы