Как получить первичный ключ в Entity Framework 4.1, то есть использовать DbContext
Ответы, которые я вижу здесь, для ObjectContext. Есть ли свойство для определения имен первичных ключей сущности при использовании DbContext?
Ах.. в один из тех случаев, когда я хочу, чтобы Entity Framework был с открытым исходным кодом! Я могу получить информацию об имени первичного ключа из метода .Find: -)
Ответы
Ответ 1
Вы не можете использовать DbContext
для этого - API-интерфейс DbContext - это просто тупая оболочка с самой необходимой функциональностью. Для более сложного преобразования вы должны преобразовать DbContext
обратно в ObjectContext
и использовать его. Попробуйте что-то вроде этого:
Извлечь ключевые слова :
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();
}
Здесь метод, который будет извлекать значения ключа объекта:
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));
}
Ответ 2
Решение предложенное Ladislav Mrnka, не будет работать для производных объектов как Вы не можете создать набор объектов для производный тип. Вы увидите эту ошибку:
ArgumentException: нет определенных EntitySet для указанного тип объекта... Если... является производным типом, используйте базовый тип. Имя параметра: TEntity
Вот мое решение, не позволяющее создать набор объектов:
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();
}
Ответ 3
вы можете попасть в ObjectContext, потому что DbContext в основном обертывает ObjectContext...
см
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
Ответ 4
Вы можете найти значение первичного ключа из класса EntityKey (http://msdn.microsoft.com/en-us/library/system.data.entitykey.aspx).
и вы можете найти объект EntityKey из DbContext следующим образом:
ObjectContext context = ((IObjectContextAdapter)dbContext).ObjectContext;
EntityKey key = context.ObjectStateManager.GetObjectStateEntry(model).EntityKey;
Ответ 5
Вот что я сделал, чтобы убедиться, что у меня есть ключ. Это по сути то же самое, что @Agus Syahputra отвечает одним важным отличием. Я добавил весь ответ ниже.
Примечание. Я тестировал это только на EF6, и я не уверен, что это работает с более ранними версиями 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;