如何使用 Entity Framework Core 获取主键值
Posted
技术标签:
【中文标题】如何使用 Entity Framework Core 获取主键值【英文标题】:How to get primary key value with Entity Framework Core 【发布时间】:2015-08-21 17:24:04 【问题描述】:我们目前正在使用下面的方法,它依赖于抽象存储库中的 IObjectContextAdapter。从我正在阅读的内容来看,与 ObjectContext 相关的任何内容似乎都已从 Entity Framework Core 中删除。下面的方法是我们唯一依赖与 ObjectContext 相关的任何东西的地方。
我们想升级到 Entity Framework Core。这是我们唯一的路障。有没有办法通过Entity Framework Core api获取实体的主键值?
// Entity Framework
public virtual int GetKey(T entity)
var oContext = ((IObjectContextAdapter)_DbContext).ObjectContext;
var oSet = oContext.CreateObjectSet<T>();
var keyName = oSet.EntitySet.ElementType
.KeyMembers
.Select(k => k.Name)
.Single();
return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
【问题讨论】:
var entry = _dbContext.Entry(entity); entry.Metadata.FindPrimaryKey().Properties.Select(p => entry.Property(p.Name).CurrentValue);
【参考方案1】:
我也遇到了类似的问题,找到了以下解决方案
// Entity Framework Core
public virtual int GetKey<T>(T entity)
var keyName = Context.Model.FindEntityType(typeof (T)).FindPrimaryKey().Properties
.Select(x => x.Name).Single();
return (int)entity.GetType().GetProperty(keyName).GetValue(entity, null);
【讨论】:
感谢您的回答。看起来它应该工作。我目前不在那个项目上,但我希望在不久的将来会回来。我会尽快尝试。 是EF7中添加的Context.Model吗?我正在尝试在 EF6 环境中进行更改,但由于该属性不存在而中断。 是的,这是 EF7(核心)属性 在 EntityFrameworkCore v1.1.2 中,FindEntityType() 的签名只需要一个字符串作为实体类型名称。 ... Context.Model.FindEntityType(typeof(T).Name).FindPrimaryKey()... 似乎被 Core 2.1 破坏了。现在只返回空值。【参考方案2】:至少在 EF Core 2.1 中,您可以通过这种方式获取密钥:
var entry = dbContext.Entry(entity);
object[] keyParts = entry.Metadata.FindPrimaryKey()
.Properties
.Select(p => entry.Property(p.Name).CurrentValue)
.ToArray();
这允许您获取创建为 shadow 属性的密钥。
我不知道调用Property(p.Name).CurrentValue
的性能如何,但是仍然可以缓存键的属性名称:
private static readonly ConcurrentDictionary<Type,string[]> KeyPropertiesByEntityType = new ConcurrentDictionary<Type, string[]>();
public object[] KeyOf<TEntity>(TEntity entity) where TEntity : class
Guard.ArgumentNotNull(entity, nameof(entity));
var entry = _dbContext.Entry(entity);
var keyProperties = KeyPropertiesByEntityType.GetOrAdd(
entity.GetType(),
t => entry.Metadata.FindPrimaryKey().Properties.Select(property => property.Name).ToArray());
var keyParts = keyProperties
.Select(propertyName => entry.Property(propertyName).CurrentValue)
.ToArray();
return keyParts;
public TKey KeyOf<TEntity, TKey>(TEntity entity) where TEntity : class
var keyParts = KeyOf(entity);
if (keyParts.Length > 1)
throw new InvalidOperationException($"Key is composite and has 'keyParts.Length' parts.");
return (TKey) keyParts[0];
【讨论】:
【参考方案3】:根据 YuriyP 的回答,您还可以获得复合键信息:
public static class Extensions
public static IEnumerable<string> FindPrimaryKeyNames<T>(this DbContext dbContext, T entity)
return from p in dbContext.FindPrimaryKeyProperties(entity)
select p.Name;
public static IEnumerable<object> FindPrimaryKeyValues<T>(this DbContext dbContext, T entity)
return from p in dbContext.FindPrimaryKeyProperties(entity)
select entity.GetPropertyValue(p.Name);
static IReadOnlyList<IProperty> FindPrimaryKeyProperties<T>(this DbContext dbContext, T entity)
return dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties;
static object GetPropertyValue<T>(this T entity, string name)
return entity.GetType().GetProperty(name).GetValue(entity, null);
然后可以像这样使用:
var keyValues = context.FindPrimaryKeyValues(entity);
var existingEntity = context.Set<TEntity>().Find(keyValues);
【讨论】:
当心 PK 是影子属性的可能性。以上是关于如何使用 Entity Framework Core 获取主键值的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework 学习系列 - 认识理解Entity Framework
如何使用 Entity Framework Core 模拟异步存储库
如何使用 Entity Framework 生成和自动递增 Id
如何使用 Entity Framework Core 正确保存 DateTime?