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 :-)
Configuring a primary key By convention, a property named Id or <type name>Id will be configured as the primary key of an entity. Owned entity types use different rules to define keys. You can configure a single property to be the primary key of an entity as follows: Data Annotations.
In order to use composite keys, Entity Framework requires you to define an order for the key properties. You can do this by using the Column annotation to specify an order. The order value is relative (rather than index based) so any values can be used. For example, 100 and 200 would be acceptable in place of 1 and 2.
DbContext generally represents a database connection and a set of tables. DbSet is used to represent a table. Your code sample doesn't fit the expected pattern.
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));
}
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With