¿Cómo obtener el nombre de la clave de entidad de ObjectSet ?

He creado un ObjectSet genérico en mi repository genérico.

Lo que me gustaría obtener es el name de la EntityKey of ObjectSet para poder usarlo en el DataContext.GetObjectByKey .

Busqué y excavé profundamente, pero parece que no puedo encontrar este valor en ninguna parte de la clase ObjectSet .

Hace un tiempo busqué una buena manera de hacer esto y no pude encontrar una. Por lo general, termino construyendo un método de extensión GetEntityByKey en algún lugar y dentro de eso, contatenando cadenas para crear claves de entidad para las 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(ObjectSet 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; } } 

Es posible que puedas hacer algo similar. Este ejemplo asume un solo campo por EntityKey para simplificar: para múltiples claves de valor, necesitaría hacer algo un poco más sofisticado con ObjectSet.ElementType.KeyMembers y pasar todas sus claves al constructor EntityKey.

Genérico:

 public class GenericoRepositorio : IGenericoRepositorio where T : class { protected readonly ObjectSet ObjetoSet; protected readonly ModeloContainer Contexto; public GenericoRepositorio(ModeloContainer contexto) { Contexto = contexto; ObjetoSet = Contexto.CreateObjectSet(); } public T Carregar(int id) { object objeto; Contexto.TryGetObjectByKey(GetEntityKey(ObjetoSet, id), out objeto); return (T)objeto; } private static EntityKey GetEntityKey(ObjectSet 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; } } 

Ver esta publicación que hice con respecto a obtener el EntitySetName. Para mi repository, creo una propiedad que obtiene el nombre del conjunto de entidades para que el nombre de la clase específica haga exactamente lo que está tratando de hacer.

Esto debería darle todos los argumentos generics (los tipos) para el ObjectSet:

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

Me costó mucho intentar hacer casi lo mismo, obtener el nombre y el valor de la clave principal en el tiempo de ejecución cuando se desconoce el tipo. Estaba intentando implementar un esquema de auditoría para eliminaciones, y cada solución que encuentro involucra un código superfluo que realmente no entiendo. El 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 las inserciones, por lo que si lo hace, debe inspeccionar esos valores cuidadosamente ya que pueden ser 0 o nulos.

 foreach(var entry in ChangeTracker.Entries()) { ... 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; 

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

var objSet = objContext.CreateObjectSet();

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 entry = this.context.Entry(this.dbset.Find(entityKey.EntityKeyValues.FirstOrDefault().Value)); entry.CurrentValues.SetValues(entityToUpdate); } } this.context.SaveChanges(); 

Probado con EF 6.

Devolverá una matriz de objetos para cada valor de clave principal para la DbEntityEntry dada.

Es posible que sus casos extremos no funcionen, pero para mis simples necesidades funciona muy bien.

Espero que esto ayude a alguien más.

 object[] GetPrimaryKeyValue(DbEntityEntry entry) { List key = new List(); 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(); }