Kornél Regius
Kornél Regius

Reputation: 3049

Get the primary key value of an arbitrary entity in code first

Is there such a method?

object GetPrimaryKeyValue(DbEntityEntry entry);

Or how should it be implemented?

Upvotes: 16

Views: 12412

Answers (4)

ChrisOBrien
ChrisOBrien

Reputation: 61

I know this is a bit old but I just saw this.

Heres How I did it (assumes pk is int)

public class Repository<T> : IDisposable, where T: class, new() 
{
    private int GetPrimaryKey(T item)
    {
        if (item == null)
            return -1;

        using (var db = new ApplicationContext())
        {
            ObjectSet<T> set = (db as IObjectContextAdapter).ObjectContext.CreateObjectSet<T>();
            string keyName = set.EntitySet
                .ElementType
                .KeyMembers
                .Select(x => x.Name)
                .First();
            Type type = typeof(T);
            int val = int.Parse(type.GetProperty(keyName).GetValue(item).ToString());
            return val;
        }
    }
}

Upvotes: 0

toddmo
toddmo

Reputation: 22466

You don't need an attached T item. This may be long winded, but it works.

public object[] GetPrimaryKeyValues<T>(DbContext databaseContext, T item)
{
  return ((IObjectContextAdapter)databaseContext).ObjectContext.CreateEntityKey(typeof(T).Name.Pluralize(), item).EntityKeyValues.Select(kv => kv.Value).ToArray();
}

The return type is suitable to use in a Find, for example. See, the key values is actually an array of objects.

If you need Pluralize(), here it is:

using System;
using System.Data.Entity.Design.PluralizationServices;
using System.Linq;
using System.Reflection;

namespace Atlas.Core.Kernel.Extensions
{
    public static class Strings
    {
      private static PluralizationService pluralizationService = PluralizationService.CreateService(System.Globalization.CultureInfo.CurrentUICulture);
      public static string Pluralize(this MemberInfo memberInfo)//types, propertyinfos, ect
      {
        return Pluralize(memberInfo.Name.StripEnd());
      }

      public static string Pluralize(this string name)
      {
        return pluralizationService.Pluralize(name); // remove EF type suffix, if any
      }



    }
  }

Upvotes: 0

Andrew Hook
Andrew Hook

Reputation: 1

I am also looking to find the Primary Key of an entity. I am using Generics in my repository so I don't know the Entity until runtime. The only way I have found to do this so far is with a sql statement.

public abstract class GenericRepository<T> : ApiController,IGenericRepository<T> where T : class
{


    string sqlstr = @"
        SELECT COLUMN_NAME
        FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
        WHERE OBJECTPROPERTY(OBJECT_ID(CONSTRAINT_SCHEMA + '.' + CONSTRAINT_NAME), 'IsPrimaryKey') = 1
        AND TABLE_NAME = '" + typeof(T).ToString() + "' AND TABLE_SCHEMA = 'dbo'";

    private Entities _entities = new Entities();


    public  virtual IQueryable<T> GetAll()
    {
        DbSqlQuery<T> queryTest = _entities.Set<T>().SqlQuery(sqlstr);

This is just a pratial of the full class but hopefully shows the solution I am using.

Upvotes: 0

dan
dan

Reputation: 2388

You need to cast your DbContext to IObjectContextAdapter so you can access the underlying ObjectContext which gives you access to some more advanced features hidden by DbContext.

Inside your class which derives DbContext the following method will work.

object GetPrimaryKeyValue(DbEntityEntry entry)
{
    var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);
    return objectStateEntry.EntityKey.EntityKeyValues[0].Value;
}

If there is more than one key then you should iterate over the EntityKeyValues property.

Upvotes: 31

Related Questions