Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the Primary Key(s) in Entity Framework 4.1, i.e. using DbContext

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 :-)

like image 783
Green Lantern Avatar asked Aug 02 '11 02:08

Green Lantern


People also ask

How do I set primary key in Entity Framework?

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.

How does Entity Framework define key?

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.

What is DbContext and DbSet in Entity Framework?

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.


Video Answer


2 Answers

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));
}
like image 152
Ladislav Mrnka Avatar answered Sep 22 '22 05:09

Ladislav Mrnka


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();
}
like image 20
Guillaume Avatar answered Sep 21 '22 05:09

Guillaume