2012-11-20 61 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); 
    } 
} 

相關問題