The answers I\'m seeing here are for ObjectContext. Is there a property to determine an entity\'s primary key names when using DbContext?
Ah.. one of those times tha
The solution proposed by Ladislav Mrnka won't work for derived entities as You can't create an object set for a derived type. You'll see this error :
ArgumentException: There are no EntitySets defined for the specified entity type ... If ... is a derived type, use the base type instead. Parameter name: TEntity
Here is my solution avoiding creating an object set :
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();
}
You cannot use DbContext
for that - DbContext API is just dumb wrapper with only most needed functionality. For everything more complex you must convert DbContext
back to ObjectContext
and use it. Try something like this:
Extract key names:
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();
}
Here's a method that will extract the key values of an entity:
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));
}
you can get to ObjectContext because DbContext mostly wraps ObjectContext...
see
http://msdn.microsoft.com/en-us/library/gg696590%28v=vs.103%29.aspx
http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext%28v=vs.103%29.aspx
http://msdn.microsoft.com/en-us/library/dd283139.aspx
Here is what I did to make sure that I got the key. It is essentially the same as @Agus Syahputra 's answer with one important difference. I've added the entire answer below.
Note: I've tested this only on EF6 and I'm not sure if this works with earlier versions of 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;
You could find primary key value from EntityKey class (http://msdn.microsoft.com/en-us/library/system.data.entitykey.aspx).
and you could find EntityKey object from DbContext like so :
ObjectContext context = ((IObjectContextAdapter)dbContext).ObjectContext;
EntityKey key = context.ObjectStateManager.GetObjectStateEntry(model).EntityKey;