简体   繁体   English

实体框架,获取孤儿的孩子记录/没有父母的记录

[英]Entity framework, Get orphans child records/records without parents

I have the following exception when saving database context : The relationship could not be changed because one or more of the foreign-key properties is non-nullable. 保存数据库上下文时出现以下异常:由于一个或多个外键属性不可为空,因此无法更改该关系。

As stated here , this is probably due to missing cascade delete. 如前所述这里 ,这可能是由于缺少级联删除。 However, this isn't my code and I do not know which table(s) could contain orphans records. 但是,这不是我的代码,我也不知道哪个表可以包含孤立记录。 The error message doesn't say so. 错误消息不这样说。

Is there a way to retrieve those orphans records. 有没有办法检索那些孤儿记录。 (At least know in which table they are) (至少知道它们在哪个表中)

Then I will be able to pinpoint which part of the code I need to adjust. 然后,我将能够指出需要调整的代码的哪一部分。

In the Entity Framework when you have relation many to many, and you are trying to delete from an object like parent.Children.Remove(child) this will only detach the child from the middle connection table. 在实体框架中,当您具有多对多关系时,您尝试从诸如parent.Children.Remove(child)类的对象中删除时,这只会将子项与中间连接表分离。 So you have to find the child and remove it from DbContext ChildrenToParent entity like so DbContext.ChildrenToParent.Remove(child) . 因此,您必须找到该子项并将其从DbContext ChildrenToParent实体中删除,例如DbContext.ChildrenToParent.Remove(child) If you give a some code sample and/or database diagram I think I can explain it more precise. 如果您提供一些代码示例和/或数据库图,我想我可以更准确地解释一下。

Can you try the following solution? 您可以尝试以下解决方案吗? The DeleteOrphans extension method must be called between DetectChanges and SaveChanges methods. 必须在DetectChanges和SaveChanges方法之间调用DeleteOrphans扩展方法。

public static class DbContextExtensions
{
    private static readonly ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>> s_navPropMappings = new ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>>();

    public static void DeleteOrphans( this DbContext source )
    {
        var context = ((IObjectContextAdapter)source).ObjectContext;
        foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
        {
            var entityType = entry.EntitySet.ElementType as EntityType;
            if (entityType == null)
                continue;

            var navPropMap = s_navPropMappings.GetOrAdd(entityType, CreateNavigationPropertyMap);
            var props = entry.GetModifiedProperties().ToArray();
            foreach (var prop in props)
            {
                NavigationProperty navProp;
                if (!navPropMap.TryGetValue(prop, out navProp))
                    continue;

                var related = entry.RelationshipManager.GetRelatedEnd(navProp.RelationshipType.FullName, navProp.ToEndMember.Name);
                var enumerator = related.GetEnumerator();
                if (enumerator.MoveNext() && enumerator.Current != null)
                    continue;

                entry.Delete();
                break;
            }
        }
    }

    private static ReadOnlyDictionary<string, NavigationProperty> CreateNavigationPropertyMap( EntityType type )
    {
        var result = type.NavigationProperties
            .Where(v => v.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
            .Where(v => v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || (v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne && v.FromEndMember.GetEntityType() == v.ToEndMember.GetEntityType()))
            .Select(v => new { NavigationProperty = v, DependentProperties = v.GetDependentProperties().Take(2).ToArray() })
            .Where(v => v.DependentProperties.Length == 1)
            .ToDictionary(v => v.DependentProperties[0].Name, v => v.NavigationProperty);

        return new ReadOnlyDictionary<string, NavigationProperty>(result);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM