2012-11-20 57 views
1

我已经搜索了大量的时间试图找到一个满意的解决方案,以解决EF中常见的孤儿问题。Entity Framework Code First - Orphaning解决方案?

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

我的要求: -

  • 收集的清算发生在域,我想简单的能够通话清晰,没有更多的。
  • 任何逻辑,以确定是否父母和孩子之间的关系已经中断,导致删除需要封装在存储库/ DbContext中。
  • 我不想为了解决这个问题而使用任何额外的东西来“肮脏”域。这包括后面的参考。

我怀疑这个问题无法解决,因为我花了相当多的时间寻找解决方案,但是我希望没有问题!

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

谢谢。

回答

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); 
    } 
} 

相关问题