C# EF Core-如何允许多个级联路径删除外键

C# EF Core-如何允许多个级联路径删除外键,c#,sql-server,entity-framework,.net-core,entity-framework-core,C#,Sql Server,Entity Framework,.net Core,Entity Framework Core,我在SQL Server 2019中有一个数据库,有4个表。1个用于用户,1个用于联系人,1个用于消息,以及包含联系人和消息之间关联关系的最后一个表。(见图) 联系人和消息通过外键链接到用户,因此当用户被删除时,它将级联删除联系人和消息 邮件可以链接多个联系人,但并非所有联系人都链接到邮件 邮件可能根本没有联系人 我现在需要一个外键,当联系人被删除时以及消息被删除时,该外键将删除MessageContacts表中的相关记录 (请注意,这只是我为解释我的问题而设置的演示场景) 在Entity F

我在SQL Server 2019中有一个数据库,有4个表。1个用于用户,1个用于联系人,1个用于消息,以及包含联系人和消息之间关联关系的最后一个表。(见图)

联系人和消息通过外键链接到用户,因此当用户被删除时,它将级联删除联系人和消息

邮件可以链接多个联系人,但并非所有联系人都链接到邮件

邮件可能根本没有联系人

我现在需要一个外键,当联系人被删除时以及消息被删除时,该外键将删除
MessageContacts
表中的相关记录

(请注意,这只是我为解释我的问题而设置的演示场景)

在Entity Framework Core中创建此方案无效,并导致以下错误:

在表“MessageContacts”上引入外键约束“FK\u MessageContacts\u messageId”可能会导致循环或多个级联路径

请参见下面my DbContext的配置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<AppUser>(entity =>
        {
            entity.ToTable("AppUser");
            entity.HasKey(e => e.id);
        });

        modelBuilder.Entity<Message>(entity =>
        {
            entity.ToTable("Messages");
            entity.HasKey(e => e.id);
            entity.HasOne<AppUser>().WithMany().HasForeignKey(e => e.userId);
        });

        modelBuilder.Entity<Contact>(entity =>
        {
            entity.ToTable("Contacts");
            entity.HasKey(e => e.id);
            entity.HasOne<AppUser>().WithMany().HasForeignKey(e => e.userId);
        });

        modelBuilder.Entity<MessageContact>(entity =>
        {
            entity.ToTable("MessageContacts");
            entity.HasKey(e =>new {e.messageId,e.contactId });
            //Removing one of the below prevents my error, but then cascading deletions don't work
            entity.HasOne<Message>().WithMany().HasForeignKey(e => e.messageId);
            entity.HasOne<Contact>().WithMany().HasForeignKey(e => e.contactId);
        });
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
基于模型创建(modelBuilder);
modelBuilder.Entity(Entity=>
{
实体。ToTable(“AppUser”);
entity.HasKey(e=>e.id);
});
modelBuilder.Entity(Entity=>
{
实体。可转帐(“信息”);
entity.HasKey(e=>e.id);
entity.HasOne().WithMany().HasForeignKey(e=>e.userId);
});
modelBuilder.Entity(Entity=>
{
实体。可转让(“合同”);
entity.HasKey(e=>e.id);
entity.HasOne().WithMany().HasForeignKey(e=>e.userId);
});
modelBuilder.Entity(Entity=>
{
实体。ToTable(“MessageContacts”);
HasKey(e=>new{e.messageId,e.contactId});
//删除下面的一项可以防止我的错误,但是级联删除不起作用
entity.HasOne().WithMany().HasForeignKey(e=>e.messageId);
entity.HasOne().WithMany().HasForeignKey(e=>e.contactId);
});
}
联系人
消息
MessageContacts
中删除FK可防止出现错误,但删除级联无法正常工作。例如,将
MessageContacts
上的FK删除到
Messages
意味着删除消息不会删除
MessageContacts
中的相关记录,从而使我成为孤儿

注意:我隐式地设置了
.OnDelete(DeleteBehavior.Cascade)
选项,它也没有解决我的问题

所以我想我的问题是,如果没有定义多个级联路径的能力,我如何实现这一点

我希望避免在数据库中手动执行任何操作,因此所有操作都通过EF Core迁移完成(如果可能)

也许上面的整个模型都有缺陷,有人有更好的解决方案吗


提前感谢。

问题在于Microsoft的SQL Server,无法解决,除非您愿意忘记通过外键进行级联删除,而是记录要删除的记录的
Id
,然后使用它手动删除所有相关记录。这样,你就不会留下一堆孤立的唱片

这真是一种可怕的方式。最糟糕的是,SQL Server是一个付费的RDBMS,但它不允许您做一些事情,您可以使用免费的RDBMS(如MySql或MariaDB)来做这些事情

那么我的解决方案呢

再见Sql Server,你好MySql。 此解决方案的实用性取决于开发人员或管理员从一个RDBMS切换到另一个RDBMS的能力。在某些生产场景中,这可能根本不可能实现。
我希望我能提供一个更好的答案,但我不认为有更好的答案。

我怀疑你能,SQL server的一个限制是它不允许像
a->B
a->C->B
这样的FK级联链。您最好将
DeleteBehavior
设置为
NoAction
,以避免SQL server在其他情况下生成错误。除了在SQL server中实现这一点之外,别无选择?它在MySql和MariaDB(两者都是免费的)中工作得非常好,如果知道我们的付费Sql环境甚至不能做到这一点,那就太糟糕了。为了清理我的孤儿而不得不记录要删除的记录的身份,这真的很愚蠢,你不这么认为吗?@这是SqlServer的问题/功能请求。AFAIK已经多次请求它,但他们拒绝实现它。这不是sql server的问题。它是c#。在SQL Server中,您可以从表中删除一行,而该行将被删除。链接可能无法删除。例如,如果您有一个带有消息ID的表和消息表。如果删除所有John Smith消息,ID表中的一些消息将指向空消息。在c#类中,除非对象的所有链接也被删除,否则对象不会被删除。因此,在c#中,当您删除所有John Smith消息时,该行将不会被删除,除非您也从消息ID表中删除。@jdweng不确定您的意思。但这是一个SQL Server问题。任何东西都不会“指向空消息”。外键不能为空(也不应该为空)。