2012-10-12 10 views
8

Mam jednostkę, nazwijmy ją CommonEntity, która ma klucz podstawowy używany jako klucz obcy w wielu innych jednostkach. W miarę rozwoju aplikacji łącza te będą nadal się rozwijać.Struktura obiektu: Sprawdź wszystkie relacje jednostki, aby użyć klucza obcego.

Chciałbym sprawdzić, czy można bezpiecznie usunąć CommonEntity (tzn. Nie jest on używany przez żadne inne podmioty).

zdaję sobie sprawę, co mogę zrobić

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

ale mam nadzieję na drodze po prostu sprawdzić wszystkie relacje automatycznie, ponieważ nie podoba mi się pomysł posiadania wrócić i zmienić ten kod ręcznie za każdym razem, gdy dodajemy nową relację. Być może jest coś w EF4 +, że nie jestem świadomy?

Pomyślałem, że może być możliwe zastosowanie zakresu transakcji, aby po prostu spróbować usunąć obiekt i wycofać go, jeśli się nie powiedzie, ale nie byłem pewien, czy wystąpiły jakiekolwiek niepożądane skutki uboczne tego podejścia.

Czy istnieje lepsze podejście?

EDIT: Wygląda jak VS2012 wykorzystał EF5 choć projekt jest .NET 4, więc stworzył model z Poços mimo że zostały wygenerowane z DB.

Odpowiedz

8

Tylko niech to nie uda. Jeśli jednostka ma wiele relacji, ta weryfikacja może być naprawdę ciężka.

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

Jeśli pozwolę, aby to się nie powiodło, czy automatycznie wycofa wszelkie udane kaskady bez zakresu transakcji? – BenC3

+1

Znaleźliśmy odpowiedź - SaveChanges() używa transakcji, więc wszelkie awarie zostaną wycofane: http://msdn.microsoft.com/en-us/library/bb336792.aspx – BenC3

+0

Wcale nie będzie dobrze, jeśli utrzymasz swoje jednostki otwarte ! – bytecode77

4

Można spróbować to:

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

Po wykonaniu pewnych badań wydaje się, że VS2 012 używa wersji EF5, nawet jeśli kierujesz ją na .Net 4, więc krótka historia generuje dla mnie POCO, mimo że wygenerowałem model z DB, więc nie mogę przesyłać do 'IEntityWithRelationships'. Moja zła za to, że o tym nie wspomniałem! – BenC3

2

Można użyć odbicie na to (jeśli nie chcesz stosowanie „Fail Usuń na SQL”) Piszę to dlatego, że nie chcesz usunąć podmiotu, po prostu chcę wiedzieć, czy jego powiązana z żadnym lub nie !

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

zauważyć, że: Kontekst musi nie Unieszkodliwiane i Proxy musi być włączony i wiem, że będzie się wszystkie powiązane Zapis do pamięci (to jest zbyt ciężki)

+1

To naprawdę dobry sposób, myślę, zamiast robić 'MyClass.Any() || MyOtherClass.Any() 'itp itd Jedna rzecz ja dodano pomijania przypisują pozwalają zadecydować o nie uwzględniają' Property' w 'HasAnyRelation()' 'The GetManyRelatedEntityNavigatorProperties()' wygląda następująco ... 'var props = entityObj.GetType(). GetProperties (BindingFlags.Public | BindingFlags.Instance) .Where (x => x.CanWrite && xGetGetMethod(). IsVirtual && x.PropertyType.IsGenericType && (x.GetCustomAttribute (typeof (IgnoreIsDeletableAttribute)) == null) ); ' – Gwasshoppa

0

Pierwszy znaleźć podmiot, który chcesz usunąć, używając Znajdź w EF i przekaż encję do poniższej funkcji. Jeśli funkcja zwróci wartość true, oznacza to, że nie można go usunąć, a dane obce istnieją. Jeśli funkcja zwróci wartość false, oznacza to, że nie ma rekordów nadrzędnych lub potomnych i można je usunąć.

Powiązane problemy