Reputation: 3049
Is there such a method?
object GetPrimaryKeyValue(DbEntityEntry entry);
Or how should it be implemented?
Upvotes: 16
Views: 12412
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
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
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
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