2012-10-12 86 views
8

我有一個實體,我們稱之爲CommonEntity,它具有在許多其他實體中用作外鍵的主鍵。隨着應用程序的開發,這些鏈接將繼續增長。實體框架:檢查實體的所有外鍵使用關係

我想要一種方法來看看CommonEntity是否可以安全刪除(即它不被任何其他實體使用)。

我知道我能做到

if(!ce.EntityA.Any() && !ce.EntityB.Any() ... && !ce.EntityN.Any()) 
{ 
    //Delete 
} 

,但我希望有一個辦法只有自動檢查所有的關係,因爲我不喜歡有回來的想法,並更改此代碼每次我們添加一個新的關係時手動。也許EF4 +中有些東西我不知道?

我認爲有可能使用事務範圍來嘗試刪除對象,並在對象失敗時將其回滾,但我不確定這種方法是否存在任何不良副作用。

有沒有更好的方法?

編輯:看起來像VS2012已經使用EF5,即使該項目是.Net 4,所以它創建了POCO模型,即使它是從DB生成的。

回答

8

就讓它失敗。如果實體有很多關係,那麼驗證可能非常重要。

public bool TryDelete(int id) 
{ 
    try 
    { 
     // Delete 
     return true; 
    } 
    catch (SqlException ex) 
    { 
     if (ex.Number == 547) return false; // The {...} statement conflicted with the {...} constraint {...} 
     throw; // other error 
    } 
} 
+0

如果我讓它失敗,它會自動回滾沒有事務範圍的任何成功的級聯嗎? – BenC3

+1

找到答案--SaveChanges()使用一個事務,所以任何失敗都會回滾:http://msdn.microsoft.com/en-us/library/bb336792.aspx – BenC3

+0

如果你讓你的實體保持打開! – bytecode77

4

你可以試試這個:

var allrelatedEnds = ((IEntityWithRelationships)ce).RelationshipManager.GetAllRelatedEnds(); 
bool hasRelation = false; 
foreach (var relatedEnd in allrelatedEnds) 
{ 
    if (relatedEnd.GetEnumerator().MoveNext()) 
    { 
     hasRelation = true; 
     break; 
    } 
} 

if (!hasRelation) 
{ 
    //Delete 
} 
+0

做了一些研究後,看來VS2 012即使在瞄準.Net 4時也會使用EF5版本,所以長話短說,即使我從數據庫生成了模型,它也會生成POCO,所以我無法投射到「IEntityWithRelationships」。我不好意思提到它! – BenC3

2

您可以使用反射這個(如果你不希望使用「fail刪除在SQL」) 我寫這篇文章,因爲我不想刪除實體,只是想知道,如果它與任何或不!

public static object GetEntityFieldValue(this object entityObj, string propertyName) 
     { 
      var pro = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).First(x => x.Name == propertyName); 
      return pro.GetValue(entityObj, null); 

     } 

public static IEnumerable<PropertyInfo> GetManyRelatedEntityNavigatorProperties(object entityObj) 
     { 
      var props = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite && x.GetGetMethod().IsVirtual && x.PropertyType.IsGenericType == true); 
      return props; 
     } 

public static bool HasAnyRelation(object entityObj) 
     { 

       var collectionProps= GetManyRelatedEntityNavigatorProperties(entityObj); 


       foreach (var item in collectionProps) 
       { 
        var collectionValue = GetEntityFieldValue(entityObj,item.Name); 
        if (collectionValue != null && collectionValue is IEnumerable) 
        { 
         var col = collectionValue as IEnumerable; 
         if (col.GetEnumerator().MoveNext()) 
         { 
          return true; 
         } 

        } 
       } 
       return false; 
} 

注意的是:上下文必須不設置和代理必須啓用 並知道它會得到所有相關的記錄,以MEMORY(太重了)

+1

這是一個非常好的方式,我認爲,而不是做'MyClass.Any()|| MyOtherClass.Any()'等等 我添加的一件事是一個Ignore屬性,允許你決定不在'HasAnyRelation()'中包含'Property'''GetManyRelatedEntityNavigatorProperties()'看起來像這樣... 'var props = entityObj。GetType()。GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite && x.GetGetMethod()。IsVirtual && x.PropertyType.IsGenericType && (x.GetCustomAttribute(typeof(IgnoreIsDeletableAttribute)) == null) );' – Gwasshoppa

0

首先找到您要使用刪除實體在EF中查找並將實體傳遞給下面的函數。如果函數返回true,則意味着不能刪除並且存在外部數據。如果函數返回false,則表示沒有父或子記錄並且可以刪除。

public static bool DeleteCheckOnEntity(object entity) 
    { 
    var propertiesList = entity.GetType().GetProperties(); 
    return (from prop in propertiesList where prop.PropertyType.IsGenericType select prop.GetValue(entity) into propValue select propValue as IList).All(propList => propList == null || propList.Count <= 0); 
    }