Я знаю, что есть несколько вопросов относительно этого сообщения об ошибке, но я не нашел ничего, что могло бы мне помочь. У меня такая ситуация:
Модель пользователя
public class User : IdentityUser<int>
{
......
public virtual ICollection<Like> Likers { get; set; }
public virtual ICollection<Like> Likees { get; set; }
public virtual ICollection<Message> MessagesSent { get; set; }
public virtual ICollection<Message> MessagesReceived { get; set; }
}
Как модель
public class Like
{
public int LikerId { get; set; }
public int LikeeId { get; set; }
public virtual User Liker { get; set; }
public virtual User Likee { get; set; }
}
Модель сообщения
public class Message
{
public int Id { get; set; }
public int SenderId { get; set; }
public virtual User Sender { get; set; }
public int RecipientId { get; set; }
public virtual User Recipient { get; set; }
.....
}
В DataContext
.....
builder.Entity<Like>()
.HasKey(k => new { k.LikerId, k.LikeeId });
builder.Entity<Like>()
.HasOne(u => u.Likee)
.WithMany(u => u.Likers)
.HasForeignKey(u => u.LikeeId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<Like>()
.HasOne(u => u.Liker)
.WithMany(u => u.Likees)
.HasForeignKey(u => u.LikerId)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<Message>()
.HasOne(u => u.Sender)
.WithMany(u => u.MessagesSent)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<Message>()
.HasOne(u => u.Recipient)
.WithMany(u => u.MessagesReceived)
.OnDelete(DeleteBehavior.Cascade);
.....
Если у меня есть .OnDelete(DeleteBehavior.Cascade);
, я получаю это сообщение об ошибке, когда пытаюсь применить миграцию: An error occured during migration Introducing FOREIGN KEY constraint 'FK_Likes_AspNetUsers_LikerId' on table 'Likes' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Одна и та же ошибка для таблиц лайков и сообщений .
Решением будет добавить .OnDelete(DeleteBehavior.Restrict);
, но если я хочу добавить опцию в приложении к удалить пользователя, я не могу этого сделать, если пользователю кто-то понравился или он отправил сообщение. Сначала мне нужно будет вручную удалить все его лайки и его сообщения, а затем выполнить удаление пользователя, поэтому я хочу сделать это автоматически с помощью Cascade Delete.
Это сообщение об ошибке появляется только тогда, когда я использую Microsoft SQL Сервер, он работает с SQLite.
Изменить: В качестве обходного пути я выбрал то, что предлагал @lauxjpn, и изменил его с .OnDelete(DeleteBehavior.Delete);
на .OnDelete(DeleteBehavior.Restrict);
и создал БД Триггер для обработки удаления дочерних записей (лайков и сообщений) перед удалением родительской. Я протестировал этот подход, и он работает. Сначала я вошел в систему с новым пользователем, кому-то понравился и отправил сообщение, а затем удалил свою учетную запись. Об остальном позаботился триггер, удалил записи из понравившихся и сообщений, а затем пользователя из AspNetUsers.
Это триггер:
CREATE TRIGGER [DELETE_User]
ON [dbo].[AspNetUsers]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM [dbo].[Likes] WHERE LikerId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Likes] WHERE LikeeId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Messages] WHERE SenderId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Messages] WHERE RecipientId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[AspNetUsers] WHERE Id IN (SELECT Id FROM DELETED)
END
Edit 2: (Может кому еще это понадобится) Триггер также можно добавить в миграцию:
public partial class AddedInstedOfTrigger : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"
CREATE OR ALTER TRIGGER [DELETE_User]
ON [dbo].[AspNetUsers]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM [dbo].[Likes] WHERE LikerId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Likes] WHERE LikeeId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Messages] WHERE SenderId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[Messages] WHERE RecipientId IN (SELECT Id FROM DELETED)
DELETE FROM [dbo].[AspNetUsers] WHERE Id IN (SELECT Id FROM DELETED)
END");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"DROP TRIGGER [DELETE_User]");
}
}