2010-07-25 14 views
6

He creado un genérico ObjectSet<T> en mi repositorio genérico.¿Cómo obtener el nombre de la clave de entidad de ObjectSet <T>?

Lo que me gustaría obtener es el name de la EntityKey de ObjectSet<T> para que pueda usarlo en el DataContext.GetObjectByKey.

He buscado y cavado profundo, pero parece que no puedo encontrar este valor en ninguna parte de la clase ObjectSet.

Respuesta

5

Hace un tiempo busqué una buena forma de hacer esto y no pude encontrar uno. En general, termino construyendo un método de extensión GetEntityByKey en algún lugar y dentro de eso, contactando cadenas para construir claves de entidad para llamadas TryGetObjectByKey. La idea general para construir la clave de entidad es algo como esto:

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

Puede hacer algo similar. Este ejemplo asume un solo campo por EntityKey por simplicidad: para las claves de valores múltiples, necesitaría hacer algo un poco más sofisticado con ObjectSet<T>.ElementType.KeyMembers y pasar todas sus claves al constructor de EntityKey.

1

Consulte this post que hice para obtener el EntitySetName. Para mi repositorio, creo una propiedad que obtiene el nombre del conjunto de entidades para el nombre de clase específico para hacer exactamente lo que está tratando de hacer.

2

genérico:

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

Esto debe darle todos los argumentos genéricos (los tipos) para la ObjectSet:

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

tuve un momento difícil tratando de hacer casi lo mismo, conseguir el nombre y el valor de la clave primaria en tiempo de ejecución cuando el tipo es desconocido. Simplemente intenté implementar un esquema de auditoría para las eliminaciones, y cada solución que encuentro implica un código superfluo que realmente no entiendo. EntityKey no está disponible desde un DbContext, que también es confuso y molesto. Las últimas 5 líneas pueden ahorrarle 5 horas y 1 año de calvicie. No estoy intentando esto para Inserts, así que si lo hace, debe inspeccionar cuidadosamente esos valores, ya que pueden ser 0 o nulos.

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

¿Qué sucede si no tiene ningún ChangeTracker.Entries? – ProfK

+0

En mi caso, me enganché en el evento SaveChanges y no deshabilité el seguimiento de cambios. Si su seguimiento de cambios está deshabilitado, entonces la respuesta marcada debería ayudarlo. Si su seguimiento de cambios no está deshabilitado, y tiene un control sobre una entidad, creo que podría sub en mi segunda línea donde puse '(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

Probado con EF 6.

Devolverá una matriz de objetos para cada valor de clave primaria para el DbEntityEntry dado.

Sus casos de borde tal vez donde esto no funciona, pero para mis necesidades simples funciona muy bien.

Espero que esto ayude a alguien más.

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(); 
} 
Cuestiones relacionadas