在表“y”上引入外键约束“x”可能会导致循环或多个级联路径

mznpcxlj  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(357)

我知道关于这个错误消息有多个问题,但是我没有找到对我有帮助的东西。
我有这样的情况:
用户模型

  1. public class User : IdentityUser<int>
  2. {
  3. ......
  4. public virtual ICollection<Like> Likers { get; set; }
  5. public virtual ICollection<Like> Likees { get; set; }
  6. public virtual ICollection<Message> MessagesSent { get; set; }
  7. public virtual ICollection<Message> MessagesReceived { get; set; }
  8. }

相似模型

  1. public class Like
  2. {
  3. public int LikerId { get; set; }
  4. public int LikeeId { get; set; }
  5. public virtual User Liker { get; set; }
  6. public virtual User Likee { get; set; }
  7. }

消息模型

  1. public class Message
  2. {
  3. public int Id { get; set; }
  4. public int SenderId { get; set; }
  5. public virtual User Sender { get; set; }
  6. public int RecipientId { get; set; }
  7. public virtual User Recipient { get; set; }
  8. .....
  9. }

在datacontext中

  1. .....
  2. builder.Entity<Like>()
  3. .HasKey(k => new { k.LikerId, k.LikeeId });
  4. builder.Entity<Like>()
  5. .HasOne(u => u.Likee)
  6. .WithMany(u => u.Likers)
  7. .HasForeignKey(u => u.LikeeId)
  8. .OnDelete(DeleteBehavior.Cascade);
  9. builder.Entity<Like>()
  10. .HasOne(u => u.Liker)
  11. .WithMany(u => u.Likees)
  12. .HasForeignKey(u => u.LikerId)
  13. .OnDelete(DeleteBehavior.Cascade);
  14. builder.Entity<Message>()
  15. .HasOne(u => u.Sender)
  16. .WithMany(u => u.MessagesSent)
  17. .OnDelete(DeleteBehavior.Cascade);
  18. builder.Entity<Message>()
  19. .HasOne(u => u.Recipient)
  20. .WithMany(u => u.MessagesReceived)
  21. .OnDelete(DeleteBehavior.Cascade);
  22. .....

如果我有 .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. likes和messages表都有相同的错误。
解决办法是 .OnDelete(DeleteBehavior.Restrict); ,但是如果我想在应用程序中添加一个选项来删除某个用户,那么如果该用户喜欢某个人或者他发送了一条消息,我就不能这样做。首先,我需要手动删除他所有的喜欢和他的消息,然后再执行用户删除,这就是为什么我想这与级联删除自动。
此错误消息仅在我使用microsoft sql server时出现,它与sqlite一起工作。
编辑:作为一种解决方法,我选择了@lauxjpn所建议和更改的内容 .OnDelete(DeleteBehavior.Delete);.OnDelete(DeleteBehavior.Restrict); 并创建了一个db触发器,用于在删除父记录之前处理子记录(like和messages)的删除。
我测试了这个方法,它是有效的。首先我用一个新用户登录,喜欢某人并发送了一条消息,然后我删除了我的帐户。触发器处理其余的内容,从likes和messages中删除记录,然后从aspnetusers中删除用户。
这是触发器:

  1. CREATE TRIGGER [DELETE_User]
  2. ON [dbo].[AspNetUsers]
  3. INSTEAD OF DELETE
  4. AS
  5. BEGIN
  6. SET NOCOUNT ON;
  7. DELETE FROM [dbo].[Likes] WHERE LikerId IN (SELECT Id FROM DELETED)
  8. DELETE FROM [dbo].[Likes] WHERE LikeeId IN (SELECT Id FROM DELETED)
  9. DELETE FROM [dbo].[Messages] WHERE SenderId IN (SELECT Id FROM DELETED)
  10. DELETE FROM [dbo].[Messages] WHERE RecipientId IN (SELECT Id FROM DELETED)
  11. DELETE FROM [dbo].[AspNetUsers] WHERE Id IN (SELECT Id FROM DELETED)
  12. END

编辑2:(也许其他人会需要这个)
也可以在迁移中添加触发器:

  1. public partial class AddedInstedOfTrigger : Migration
  2. {
  3. protected override void Up(MigrationBuilder migrationBuilder)
  4. {
  5. migrationBuilder.Sql(@"
  6. CREATE OR ALTER TRIGGER [DELETE_User]
  7. ON [dbo].[AspNetUsers]
  8. INSTEAD OF DELETE
  9. AS
  10. BEGIN
  11. SET NOCOUNT ON;
  12. DELETE FROM [dbo].[Likes] WHERE LikerId IN (SELECT Id FROM DELETED)
  13. DELETE FROM [dbo].[Likes] WHERE LikeeId IN (SELECT Id FROM DELETED)
  14. DELETE FROM [dbo].[Messages] WHERE SenderId IN (SELECT Id FROM DELETED)
  15. DELETE FROM [dbo].[Messages] WHERE RecipientId IN (SELECT Id FROM DELETED)
  16. DELETE FROM [dbo].[AspNetUsers] WHERE Id IN (SELECT Id FROM DELETED)
  17. END");
  18. }
  19. protected override void Down(MigrationBuilder migrationBuilder)
  20. {
  21. migrationBuilder.Sql(@"DROP TRIGGER [DELETE_User]");
  22. }
  23. }
xurqigkl

xurqigkl1#

我最近在这里回答了同样的问题,所以:
你不需要丢掉任何外键。只是使用 OnDelete(DeleteBehavior) 明确指定需要哪种级联行为。
例如,以下情况将导致成功创建模型,但对于实际应用程序,您需要自行决定在何处以及如何中断级联:

  1. builder.Entity<PhotoDevice>()
  2. .HasOne(bc => bc.Photo)
  3. .WithMany(b => b.PhotoDevices)
  4. .HasForeignKey(bc => bc.PhotoRef)
  5. .OnDelete(DeleteBehavior.Restrict); // <-- define cascading behavior

有关详细信息,请参见关系:级联删除和级联删除。
这不是ef核心,而是sql server限制(因此,sql server也会引发异常)。
下面是更多的资源,它们处理这个限制,并展示如何使用 INSTEAD OF 触发器,如果中断级联不是您可以接受的选项:
使用触发器解决sql server多级联路径问题
避免循环/多个更新路径的首选设计

相关问题