Reputation: 868
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 that I wish Entity Framework is open source! I can glean this primary key name information from .Find method :-)
Upvotes: 14
Views: 9128
Reputation: 364249
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));
}
Upvotes: 26
Reputation: 13128
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();
}
Upvotes: 4
Reputation: 21
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;
Upvotes: 1
Reputation: 436
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;
Upvotes: 1
Reputation: 70369
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
Upvotes: 1