2011-08-31 13 views

Odpowiedz

50

Można zapytać metadanych mapowania dostać nazwiska kluczowych właściwości (nie może być więcej niż jeden):

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; 
ObjectSet<YourEntity> set = objectContext.CreateObjectSet<YourEntity>(); 
IEnumerable<string> keyNames = set.EntitySet.ElementType 
              .KeyMembers 
              .Select(k => k.Name); 

Gdy masz nazwy klawiszy można wykorzystać odbicie na dostęp do ich wartości.

Jak widać, podejście powraca do ObjectContext API, ponieważ interfejs API DbContext jest przeznaczony tylko dla prostych scenariuszy, w których nie przeszkadza się takim szczegółom, jak odwzorowywanie metadanych.

+1

Thx. oznaczony jako odpowiedź. Chciałbym skomentować, że lepszym rozwiązaniem jest dodanie interfejsu do klasy kontekstu (np. IYourDataContext) i dziedziczenie IObjectContextAdapter do tego IYourDataContext. W ten sposób nie musisz go rzucać. –

+0

Biorąc pod uwagę, że teraz jest 5 lat, czy istnieje sposób, aby to zrobić bez ciężkiej refleksji? Kontekstem mojego pytania jest próba implementacji metody Find bez śledzenia, takiej jak SingleOrDefault(), ale w klasie bazowej, która nie może zakładać, że zna nazwę klucza jednostki. Dzięki chłopaki. –

+0

wielkie dzięki, działaj jak czar –

22

W przypadku pomaga nikomu, muszę być w stanie to zrobić bez znając typ wcześniej (więc nie mogłem łatwo zrobić CreateObjectSet<YourEntity>() bo nie wiem YourEntity), więc byłem w stanie dostosować @Ladislav „s rozwiązanie na następujące:

// variable "type" is a System.Type passed in as a method parameter 
ObjectContext objectContext = ((IObjectContextAdapter)this.context).ObjectContext; 
IEnumerable<string> retval = (IEnumerable<string>)objectContext.MetadataWorkspace 
    .GetType(type.Name, type.Namespace, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace) 
    .MetadataProperties 
    .Where(mp => mp.Name == "KeyMembers") 
    .First() 
    .Value; 

Wydaje się trochę dziwne, że MetadataWorkspace.GetType wymaga ciągi nazwą typu i nazw, zamiast System.Type, ale to najlepsze co mogłem znaleźć.

+0

Dzięki, uratowałeś mi życie! –

7

Wystąpił problem z obu powyższych podejść z powodu dziedziczenia Tabela na typ. Moja wersja pracy (w przeliczeniu na użytkownika @ S'pht'Kr rozwiązanie, ale przy użyciu DataSpace.OSpace nie DataSpace.CSpace z tego powodu) jest poniżej:

 protected IEnumerable<string> GetKeyPropertyNames() 
     { 
      var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter) this.Context).ObjectContext; 

      return GetKeyPropertyNames(typeof (TEntity), objectContext.MetadataWorkspace); 
     } 

     private static IEnumerable<string> GetKeyPropertyNames(Type type, MetadataWorkspace workspace) 
     { 
      EdmType edmType; 

      if (workspace.TryGetType(type.Name, type.Namespace, DataSpace.OSpace, out edmType)) 
      { 
       return edmType.MetadataProperties.Where(mp => mp.Name == "KeyMembers") 
        .SelectMany(mp => mp.Value as ReadOnlyMetadataCollection<EdmMember>) 
        .OfType<EdmProperty>().Select(edmProperty => edmProperty.Name); 
      } 

      return null; 
     } 
+0

Awesome.to pomogło mi –

9

W EF 6.1 istnieje metoda Db() rozszerzenie, które sprawia, że ​​to łatwiejsze.

Przykład:

public static IEnumerable<string> GetPrimaryKeyPropertyNames(DbContext db, Type entityType) 
{ 
    return db.Db(entityType).Pks.Select(x => x.PropertyName); 
} 
+0

Jaka jest wydajność? Ciężki z podstawowym odbiciem? –

+0

Nie mam pojęcia, EntityFramework jest do mojej wiedzy w oparciu o wiele refleksji na początek. – angularsen

+0

anjdreas: Dobra uwaga. –

2

Jak rashleighp użytkownika Chciałem też wariant użytkownik Ladislav Mrnka użytkownika odpowiedź, która musi tylko znać typ w środowisku wykonawczym, zamiast znać typ w czasie kompilacji. Podobnie jak użytkownik rashleighp, rozwiązanie użytkownika S'pht'Kr nie działało dla mnie, ale jego rozwiązanie zadziałało. Poniżej przyczyniam się do tej rozmowy, dostarczając prostszą wersję jego odpowiedzi, która sprawdziła się dla mnie. Jednak właśnie dowiedziałem się o rozwiązaniu przez użytkownika anjdreas i to jest to, z którego będę korzystał.

// variable "type" is a System.Type passed in as a method parameter 
((IObjectContextAdapter)context) 
    .ObjectContext 
    .MetadataWorkspace 
    .GetItem<EntityType>(type.FullName, DataSpace.OSpace) 
    .KeyProperties 
    .Select(p => p.Name); 
Powiązane problemy