2011-08-02 17 views
14

Las respuestas que estoy viendo aquí son para ObjectContext. ¿Existe una propiedad para determinar los nombres de las principales claves de una entidad cuando se utiliza DbContext?Cómo obtener la clave principal (s) en Entity Framework 4.1, es decir, utilizando DbContext

Ah ... ¡una de esas veces que deseo Entity Framework es de código abierto! Puedo recoger esta información de nombre de clave principal de método .find :-)

+1

Usted puede ver el código fuente en http://entityframework.codeplex.com/ – VahidNaderi

Respuesta

26

No puede usar DbContext para eso - La API DbContext es simplemente un envoltorio estúpido con la funcionalidad más necesaria. Para todo lo más complejo, debe convertir DbContext a ObjectContext y usarlo. Intentar algo como esto:

Extracto nombres clave:

public static string[] GetEntityKeyNames<TEntity>(this DbContext context) where TEntity : class 
{ 
    if (context == null) 
    throw new ArgumentNullException("context"); 

    var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<TEntity>(); 
    var entitySet = set.EntitySet; 
    return entitySet.ElementType.KeyMembers.Select(k => k.Name).ToArray(); 
} 

Aquí es un método que se va a extraer los valores clave de una entidad:

public static IEnumerable<object> GetEntityKeys<TEntity>(this DbContext context, TEntity entity) 
    where TEntity : class 
{ 
    if (context == null) 
    throw new NullReferenceException("context"); 

    var type = typeof(TEntity); 

    var set = ((IObjectContextAdapter)context).ObjectContext.CreateObjectSet<TEntity>(); 
    var entitySet = set.EntitySet; 
    var keys = entitySet.ElementType.KeyMembers; 
    var props = keys.Select(k => type.GetProperty(k.Name)); 
    return props.Select(p => p.GetValue(entity)); 
} 
+0

que funcionó ... de nuevo un mensaje Lad que me ayudó thx +1 –

+2

No creo que esto trabajo si TEntity es clase derivada.¿Hay alguna manera de hacerlo sin CreateObjectSet ? –

+2

En caso de que alguien más intente esto (EF 6) y reciba un mensaje que diga: El tipo 'TEntity' debe ser un tipo de referencia para usarlo como parámetro ... requiere una restricción 'donde TEntity: class'. CreateObjectSet signature y def: http://msdn.microsoft.com/en-us/library/dn236948%28v=vs.113%29.aspx –

1
+0

ya sé que (' (db como IObjectContextAdapter) .ObjectContext'), estoy tratando de averiguar cómo obtener los nombres de las principales claves de una entidad –

+0

Aquí está el enfoque anterior, pero llega a la base de datos http://stackoverflow.com/questions/2958921/ entity-framework-4-how-to-find-the-primary-key/2959046 # 2959046 –

1

Usted puede encontrar valor de la clave primaria de la clase EntityKey (http://msdn.microsoft.com/en-us/library/system.data.entitykey.aspx).

y se podía encontrar el objeto de EntityKey DbContext así:

ObjectContext context = ((IObjectContextAdapter)dbContext).ObjectContext; 
EntityKey key = context.ObjectStateManager.GetObjectStateEntry(model).EntityKey; 
+1

@agussyahpurta Esto solo funcionará en el caso de que el administrador de estado de objetos tenga estado para el objeto modelo; de lo contrario, se bloqueará –

1

Aquí es lo que hice para asegurarse de que me dieron la llave. Es esencialmente lo mismo que la respuesta de @Agus Syahputra con una diferencia importante. He agregado toda la respuesta a continuación.

Nota: He probado esto solo en EF6 y no estoy seguro si esto funciona con versiones anteriores de EF.

//I'm currently inside savechanges of my dbcontext 
//if you're typing this code outside your dbcontext, replace this with your dbcontext  
var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity); 
    string keyName = objectStateEntry.EntityKey.EntityKeyValues[0].Key; 
+0

, esta debería ser la respuesta correcta – gidanmx2

4

El solution proposed by Ladislav Mrnka no funcionará para entidades derivadas como You can't create an object set for a derived type. Verá este error:

ArgumentException: No hay EntitySets definidos para el tipo de entidad especificada ... Si ... es un tipo derivado, utilizar el tipo de base en lugar . Nombre de parámetro: TEntity

Aquí está mi solución evitando la creación de un conjunto de objetos:

public string[] GetEntityKeyNames<TEntity>(DbContext context) 
{ 
    if (context == null) 
    { 
     throw new ArgumentNullException("context"); 
    } 
    var objectContext = ((IObjectContextAdapter)Context).ObjectContext; 
    //We must use the namespace of the context and the type name of the entity 
    string entityTypeName = context.GetType().Namespace + '.' + typeof(TEntity).Name; 
    var entityType = objectContext.MetadataWorkspace.GetItem<EntityType>(entityTypeName, DataSpace.CSpace); 
    return entityType.KeyProperties.Select(k => k.Name).ToArray(); 
} 
Cuestiones relacionadas