2010-07-25 8 views
6

Ho creato un generico ObjectSet<T> nel mio repository generico.Come ottenere il nome chiave dell'entità ObjectSet <T>?

Quello che mi piacerebbe ottenere è il name di EntityKey di ObjectSet<T> in modo che io possa usarlo nello DataContext.GetObjectByKey.

Ho cercato in giro e ho scavato in profondità, ma non riesco a trovare questo valore da nessuna parte nella classe ObjectSet.

risposta

5

Mi è sembrato un po 'di tempo fa per un bel modo di farlo e non sono riuscito a trovarne uno. Generalmente finisco per creare un metodo di estensione GetEntityByKey da qualche parte e al suo interno, contatenando le stringhe per creare chiavi di entità per le chiamate TryGetObjectByKey. L'idea generale per la creazione della chiave dell'entità è simile a questa:

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var dc = new AdventureWorksLT2008Entities(); 
     object c; 
     dc.TryGetObjectByKey(GetEntityKey(dc.Customers, 23), out c); 
     var customer = c as Customer; 
     Console.WriteLine(customer.EmailAddress); 
    } 

    private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class 
    { 
     var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name; 
     var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString(); 
     var entityKey = new EntityKey(entitySetName, new[] {new EntityKeyMember(keyPropertyName, keyValue)}); 
     return entityKey; 
    } 
} 

Potrebbe essere possibile fare qualcosa di simile. Questo esempio presuppone un singolo campo per EntityKey per semplicità: per chiavi a valore multiplo è necessario fare qualcosa di leggermente più sofisticato con ObjectSet<T>.ElementType.KeyMembers e passare tutte le chiavi nel costruttore EntityKey.

1

Vedere this post che ho apportato per ottenere EntitySetName. Per il mio repository, creo una proprietà che ottiene il nome del set di entità per il nome della classe specifica per fare esattamente ciò che si sta tentando di fare.

2

Generico:

public class GenericoRepositorio<T> : IGenericoRepositorio<T> where T : class 
{ 
    protected readonly ObjectSet<T> ObjetoSet; 
    protected readonly ModeloContainer Contexto; 

    public GenericoRepositorio(ModeloContainer contexto) 
    { 
     Contexto = contexto; 
     ObjetoSet = Contexto.CreateObjectSet<T>(); 
    } 

    public T Carregar(int id) 
    { 
     object objeto; 
     Contexto.TryGetObjectByKey(GetEntityKey(ObjetoSet, id), out objeto); 
     return (T)objeto; 
    } 

    private static EntityKey GetEntityKey<T>(ObjectSet<T> objectSet, object keyValue) where T : class 
    { 
     var entitySetName = objectSet.Context.DefaultContainerName + "." + objectSet.EntitySet.Name; 
     var keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString(); 
     var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) }); 
     return entityKey; 
    } 
} 
1

Questo dovrebbe dare tutti gli argomenti generici (i tipi) per l'ObjectSet:

objectSet.GetType().GetGenericArguments().First() 
0

ho avuto un momento difficile cercando di fare quasi la stessa cosa, ottenendo il nome e il valore della chiave primaria in fase di esecuzione quando il tipo è sconosciuto. Stavo solo cercando di implementare uno schema di auditing per le eliminazioni, e ogni soluzione che trovo implica un codice superfluo che non capisco davvero. EntityKey non è disponibile da un DbContext, che è anche confuso e fastidioso. Le ultime 5 linee potrebbero farti risparmiare 5 ore e 1 anno di calvizie. Non sto tentando di inserire Inserts, quindi se lo fai, devi controllare attentamente quei valori perché potrebbero essere 0 o null.

foreach(var entry in ChangeTracker.Entries<IAuditable>()) 
{ 
... 

case EntityState.Deleted: 

var oc = ((IObjectContextAdapter)this).ObjectContext; //this is a DbContext 
EntityKey ek = oc.ObjectStateManager.GetObjectStateEntry(entry.Entity).EntityKey; 
var tablename = ek.EntitySetName; 
var primaryKeyField = ek.EntityKeyValues[0].Key;  //assumes only 1 primary key 
var primaryKeyValue = ek.EntityKeyValues[0].Value; 
+0

Cosa succede se non si dispone di alcun ChangeTracker.Entries? – ProfK

+0

Nel mio caso sono stato collegato all'evento SaveChanges e non ho disabilitato il rilevamento delle modifiche. Se il rilevamento delle modifiche è disattivato, la risposta contrassegnata dovrebbe essere di aiuto. Se il rilevamento delle modifiche non è disabilitato e hai un handle su un'entità, penserei che potresti sottometterlo nella mia seconda linea in cui inserisco "(entry.Entity)". – Bill

0

var objContext = ((IObjectContextAdapter)this.context).ObjectContext;

var objSet = objContext.CreateObjectSet<T>();

var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entityToUpdate);

Object foundEntity;

var exits = objContext.TryGetObjectByKey(entityKey, out foundEntity);

if (exits && this.dbset.Local != null && this.dbset.Local.Contains(foundEntity) &&this.dbset.Local.Any())      
{ 
    if (entityKey.EntityKeyValues != null && entityKey.EntityKeyValues.Any())      
    {  
    DbEntityEntry<T> entry = this.context.Entry(this.dbset.Find(entityKey.EntityKeyValues.FirstOrDefault().Value)); 
         entry.CurrentValues.SetValues(entityToUpdate); 
    } 
} 

this.context.SaveChanges(); 
0

Testato con EF 6.

Restituirà una matrice di oggetti per ciascun valore di chiave primaria per DbEntityEntry specificato.

I loro casi estremi in cui ciò non funziona, ma per le mie semplici esigenze funziona alla grande.

Spero che questo aiuti qualcun altro.

object[] GetPrimaryKeyValue(DbEntityEntry entry) 
{ 
    List<object> key = new List<object>(); 

    var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity); 
    if (objectStateEntry.EntityKey.EntityKeyValues != null && objectStateEntry.EntityKey.EntityKeyValues.Length==1) 
    { 
     key.Add(objectStateEntry.EntityKey.EntityKeyValues[0].Value); 
    } 
    else 
    { 
     if (objectStateEntry.EntitySet.ElementType.KeyMembers.Any()) 
     { 
      foreach (var keyMember in objectStateEntry.EntitySet.ElementType.KeyMembers) 
      { 
       if (entry.CurrentValues.PropertyNames.Contains(keyMember.Name)) 
       { 
        var memberValue = entry.CurrentValues[keyMember.Name]; 
        if (memberValue != null) 
        { 
         key.Add(memberValue); 
        } 
       } 
      } 
     } 
    } 
    return key.ToArray(); 
} 
Problemi correlati