在table'Y'上引入FOREIGN KEY约束'X'可能会造成循环或多级联路径

Introducing FOREIGN KEY constraint 'X' on table 'Y' may cause cycles or multiple cascade paths

我知道有很多关于此错误消息的问题,但我没有找到对我有帮助的东西。
我有这种情况:

用户模型

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.
LikesMessages 表的相同错误。

一个解决方案是添加.OnDelete(DeleteBehavior.Restrict);,但是如果我想在应用程序中添加一个选项来删除用户,如果用户喜欢某人或者他发送了一个我就不能这样做信息。首先,我需要手动删除他所有的点赞和消息,然后执行用户删除,这就是为什么我想使用级联删除自动执行此操作。

此错误消息仅在我使用 Microsoft SQL 服务器时出现,它适用于 SQLite。

编辑: 作为解决方法,我选择了@lauxjpn sugested 并从 .OnDelete(DeleteBehavior.Delete); 更改为 .OnDelete(DeleteBehavior.Restrict); 并创建了一个 DB Trigger 来处理在删除父记录之前删除子记录(喜欢和消息) .
我测试了这种方法并且有效。首先,我用一个新用户登录,喜欢某人并发送了一条消息,然后我删除了我的帐户。触发器负责其余的工作,从喜欢和消息中删除记录,然后从 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

编辑 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]");
    }
}

我最近在 SO:

上给出了 to the

You don't need to drop any of your foreign keys. Just use OnDelete(DeleteBehavior) to explicitly specify what kind of cascading behavior you need.

For example, the following would result in your model being created successfully, but for your real application, you need to decide yourself where and how to break the cascade:

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

For further information, see Relationships: Cascade delete and Cascade Delete.

This is not an EF Core, but a SQL Server limitation (therefore the exception is also thrown by SQL Server).

Here are further resources, that deal with this limitation and show how to work around it, by using INSTEAD OF trigger, if breaking the cascade is not an option you can live with: