2011-08-31 17 views
28

Come faccio a sapere quale proprietà di una classe è la chiave primaria della Entity Framework Codice Prima entità POCO?Prima il codice Entity Framework. Trova chiave primaria

Si prega di notare string matching per Id/nome della classe + "Id" è una cattiva scelta. Ci deve essere un modo per estrapolare la convenzione utilizzata da Entity Framework e ottenere in modo affidabile la proprietà chiave.

Grazie in anticipo.

risposta

50

Si può chiedere i metadati di mappatura per ottenere i nomi di proprietà chiave (non ci possono essere più di uno):

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

Una volta che avete i nomi dei tasti è possibile utilizzare la reflection per accedere ai propri valori.

Come si può vedere, l'approccio ritorna all'ObjectContext API perché l'API di DbContext è solo per scenari semplici in cui non ci si preoccupa di dettagli come la mappatura dei metadati.

+1

Thx. contrassegnato come risposta. Mi piace lasciare un commento, che è una migliore idea di aggiungere un'interfaccia per la classe di contesto (ad esempio, IYourDataContext) ed ereditare l'IObjectContextAdapter a quella IYourDataContext. In questo modo non devi lanciarlo. –

+0

Dato che ora è 5 anni, c'è un modo per farlo senza un pesante riflesso? Il contesto della mia domanda è un tentativo di implementare un metodo di ricerca senza tracciamento, come SingleOrDefault() ma in una classe base che non può presumere di conoscere il nome della chiave dell'entità. Grazie ragazzi. –

+0

Grazie mille, il lavoro come un fascino –

22

In caso aiuta nessuno, avevo bisogno di essere in grado di fare questo senza la conoscenza del tipo di anticipo (quindi non ho potuto fare facilmente CreateObjectSet<YourEntity>() perché non sapevo YourEntity), quindi ero in grado di adattarsi @Ladislav 's soluzione nella seguente:

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

Sembra un po' strano che MetadataWorkspace.GetType richiede stringhe del nome del tipo e dello spazio dei nomi, invece di uno System.Type, ma questo è il migliore che ho trovato.

+0

Grazie, mi hai salvato la vita! –

7

Ho avuto problemi con entrambi gli approcci a causa della tabella per ogni tipo di ereditarietà di cui sopra. La mia versione di lavoro (sulla base di soluzione @ di S'pht'Kr ma usando DataSpace.OSpace non DataSpace.CSpace per questo motivo) è al di sotto:

 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

Fantastico.che mi ha aiutato –

9

In EF 6.1 c'è un metodo Db() estensione che rende questo più facile.

Esempio:

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

Come è la sua performance? Pesante con la riflessione sottostante? –

+0

Non ho idea, EntityFramework è a mia conoscenza basato su molte riflessioni per cominciare. – angularsen

+0

anjdreas: buon punto. –

2

Come rashleighp utente, volevo anche una variante di utente Ladislav Mrnka di risposta che ha solo bisogno di conoscere il tipo in fase di esecuzione invece di dover conoscere il tipo in fase di compilazione. Anche come utente rashleighp, la soluzione dell'utente S'pht'Kr non ha funzionato per me, ma la sua soluzione ha funzionato. Di seguito, contribuisco a questa conversazione fornendo una versione più semplice della sua risposta che ha funzionato per me. Tuttavia, ho appena saputo della soluzione per utente anjdreas e questo è quello che userò.

// 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); 
Problemi correlati