ForeignKey SetNull OnDelete

时间:2019-05-24 10:00:29

标签: sql-server entity-framework-core

我想知道在删除相关行时是否可以使用复合外键将此外键的仅一列设置为null。

实际上,第二列(我不想为空的那一列)用于其他我不想停用的外键。

精度:我使用实体框架核心(最新版本)。

3 个答案:

答案 0 :(得分:1)

据我所知这是不可能的,因为您的外键值将引用不存在的记录。但是,您可以使用以下解决方法:

另一列

您可能会创建具有相同值的另一列,而您的旧列将仅引用您要删除的表,其他表的外键将链接到具有相同值的新列

未为此表定义外键

您可以避免为可能要删除记录的表定义外键,这样就不会影响您。

关闭外键检查

这可以“解决”您的问题,但应尽可能避免。

虚拟删除

在目标表中,您可以创建一个已删除标志并将其设置为true而不是实际删除。

答案 1 :(得分:0)

感谢您的回答。

除了一件事,我同意你所说的一切:

  

据我所知这是不可能的,因为您的外键值将引用不存在的记录。

列之一为可为空的事实(我想将其设置为NULL)使我可以进行以下FK {ParentId:null,TenantId:4}不引用任何行。如果设置了ParentId,FK现在将引用一行。

在我的情况下,我只希望如果删除Parent,则仅将ParentId设置为null,而不要将用于其他某些FK以及PK中的TenantId设置为。但是我得出的结论是,您不可能...

答案 2 :(得分:0)

最后,我覆盖了SaveChanges方法以探索子级,并将FK的所有列部分都设置为null(TenantId除外)。

这是允许迭代一个实体导航属性的代码:

foreach (var navigationEntry in entry.Navigations
                            .Where(n => !n.Metadata.IsDependentToPrincipal()))
{
    if (navigationEntry is CollectionEntry collectionEntry)
    {
        // FK uses DeleteBehavior.ClientSetNull -> let's set it to NULL
        if (((Microsoft.EntityFrameworkCore.Metadata.Internal.Navigation)((MemberEntry)navigationEntry).Metadata).Builder.Metadata.ForeignKey.DeleteBehavior == DeleteBehavior.ClientSetNull)
        {
            // getting all fields composing the FK (except TenantId)
            List<string> fieldsToSetToNull = ((Microsoft.EntityFrameworkCore.Metadata.Internal.Navigation)((MemberEntry)navigationEntry).Metadata).Builder.Metadata.ForeignKey.Properties.Where(x => x.Name != nameof(IMustHaveTenant.TenantId)).Select(x => x.Name).ToList();

            List<object> dependentEntitiesList = new List<object>((IEnumerable<object>)collectionEntry.CurrentValue);
            for (var i = dependentEntitiesList.Count - 1; i >= 0; i--)
            {
                // setting all fields to NULL
                foreach (string fi in fieldsToSetToNull)
                {
                    var childEntry = this.Entry(dependentEntitiesList[i]);
                    childEntry.CurrentValues[fi] = null;
                }
            }
        }
    }
}