实体框架代码优先 - 孤立解决方案?

Posted

技术标签:

【中文标题】实体框架代码优先 - 孤立解决方案?【英文标题】:Entity Framework Code First - Orphaning solutions? 【发布时间】:2012-11-20 14:04:12 【问题描述】:

我已经搜索了很长时间,试图为 EF 中常见的孤立问题找到令人满意的解决方案。

最简单的孤立形式之一是清除实体集合。实体之间的关系已删除,但子实体仍保留在数据库中。

我的要求:-

集合的清除发生在域中,我希望能够简单地调用 clear 而不是更多。 任何判断父子关系是否被破坏导致删除的逻辑都需要封装在存储库/DbContext中。 我不想为了解决这个问题而用任何额外的东西“弄脏”域。这包括反向引用。

我怀疑这无法解决,因为我已经花费了大量时间寻找解决方案,但我是出于希望而提出的!

我查看的区域是 ChangeTracker 和我可以挂钩的任何可能的事件,类似于在各个地方弹出的 AssociationChanged 事件。 DbContext 中的某处必须知道这种关系已被破坏。如何访问它,这是个问题?

谢谢。

【问题讨论】:

【参考方案1】:

您可以尝试以下解决方案吗? Mb 它适合您的需求。必须在 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);
    

【讨论】:

以上是关于实体框架代码优先 - 孤立解决方案?的主要内容,如果未能解决你的问题,请参考以下文章

实体框架代码优先自加入,'多重性在角色中无效'

将实体框架从数据库优先转换为代码优先

使用实体框架 6 代码优先方法时,在程序集中未找到上下文类型 [重复]

实体框架代码优先:共享主键

实体框架代码优先 - 通过主键将子实体添加到父实体

如何为实体框架代码优先迁移设置隔离级别