我知道关于这个错误消息有多个问题,但是我没有找到对我有帮助的东西。
我有这样的情况:
用户模型
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.
likes和messages表都有相同的错误。
解决办法是 .OnDelete(DeleteBehavior.Restrict);
,但是如果我想在应用程序中添加一个选项来删除某个用户,那么如果该用户喜欢某个人或者他发送了一条消息,我就不能这样做。首先,我需要手动删除他所有的喜欢和他的消息,然后再执行用户删除,这就是为什么我想这与级联删除自动。
此错误消息仅在我使用microsoft sql server时出现,它与sqlite一起工作。
编辑:作为一种解决方法,我选择了@lauxjpn所建议和更改的内容 .OnDelete(DeleteBehavior.Delete);
至 .OnDelete(DeleteBehavior.Restrict);
并创建了一个db触发器,用于在删除父记录之前处理子记录(like和messages)的删除。
我测试了这个方法,它是有效的。首先我用一个新用户登录,喜欢某人并发送了一条消息,然后我删除了我的帐户。触发器处理其余的内容,从likes和messages中删除记录,然后从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]");
}
}
1条答案
按热度按时间xurqigkl1#
我最近在这里回答了同样的问题,所以:
你不需要丢掉任何外键。只是使用
OnDelete(DeleteBehavior)
明确指定需要哪种级联行为。例如,以下情况将导致成功创建模型,但对于实际应用程序,您需要自行决定在何处以及如何中断级联:
有关详细信息,请参见关系:级联删除和级联删除。
这不是ef核心,而是sql server限制(因此,sql server也会引发异常)。
下面是更多的资源,它们处理这个限制,并展示如何使用
INSTEAD OF
触发器,如果中断级联不是您可以接受的选项:使用触发器解决sql server多级联路径问题
避免循环/多个更新路径的首选设计