1

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

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

我的要求:-

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

我怀疑这无法解决,因为我花了相当多的时间寻找解决方案,但我是出于希望而提出的!

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

谢谢。

4

1 回答 1

0

您可以尝试以下解决方案吗?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);
    }
}

于 2015-09-09T17:37:40.553 回答