Entity framework 如何使用实体框架核心获取主键值
我们目前正在使用下面的方法,该方法依赖于抽象存储库中的IObjectContextAdapter。从我所阅读的内容来看,似乎任何与ObjectContext相关的内容都被从实体框架核心中切掉了。下面的方法是我们唯一依赖于任何与ObjectContext相关的东西的地方 我们想升级到实体框架核心。这是我们唯一的路障。有没有办法通过实体框架核心API获取实体主键的值Entity framework 如何使用实体框架核心获取主键值,entity-framework,primary-key,repository-pattern,entity-framework-core,Entity Framework,Primary Key,Repository Pattern,Entity Framework Core,我们目前正在使用下面的方法,该方法依赖于抽象存储库中的IObjectContextAdapter。从我所阅读的内容来看,似乎任何与ObjectContext相关的内容都被从实体框架核心中切掉了。下面的方法是我们唯一依赖于任何与ObjectContext相关的东西的地方 我们想升级到实体框架核心。这是我们唯一的路障。有没有办法通过实体框架核心API获取实体主键的值 // Entity Framework public virtual int GetKey(T entity) { var o
// 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);
}
//实体框架
公共虚拟int GetKey(T实体)
{
var oContext=((IObjectContextAdapter)_DbContext).ObjectContext;
var oSet=oContext.CreateObjectSet();
var keyName=oSet.EntitySet.ElementType
.主要成员
.选择(k=>k.Name)
.Single();
return(int)entity.GetType().GetProperty(keyName).GetValue(entity,null);
}
我也遇到了类似的问题,并找到了以下解决方案
// 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);
}
//实体框架核心
公共虚拟int GetKey(T实体)
{
var keyName=Context.Model.FindentialType(typeof(T)).FindPrimaryKey().Properties
.Select(x=>x.Name).Single();
return(int)entity.GetType().GetProperty(keyName).GetValue(entity,null);
}
根据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);
}
}
公共静态类扩展{
公共静态IEnumerable FindPrimaryKeyNames(此DbContext DbContext,T实体){
从dbContext.FindPrimaryKeyProperties(实体)中的p返回
选择p.名称;
}
公共静态IEnumerable FindPrimaryKeyValues(此DbContext DbContext,T实体){
从dbContext.FindPrimaryKeyProperties(实体)中的p返回
选择entity.GetPropertyValue(p.Name);
}
静态IReadOnlyList FindPrimaryKeyProperties(此DbContext DbContext,T实体){
返回dbContext.Model.FindentialType(typeof(T)).FindPrimaryKey().Properties;
}
静态对象GetPropertyValue(此T实体,字符串名称){
返回entity.GetType().GetProperty(name).GetValue(entity,null);
}
}
然后可以在类似的情况下使用:
var keyValues = context.FindPrimaryKeyValues(entity);
var existingEntity = context.Set<TEntity>().Find(keyValues);
var-keyValues=context.FindPrimaryKeyValues(实体);
var existingEntity=context.Set().Find(keyValues);
至少在EF Core 2.1中,您可以通过以下方式获得密钥:
var entry = dbContext.Entry(entity);
object[] keyParts = entry.Metadata.FindPrimaryKey()
.Properties
.Select(p => entry.Property(p.Name).CurrentValue)
.ToArray();
这允许您获取作为阴影属性创建的密钥。我不知道call
属性(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];
}
私有静态只读ConcurrentDictionary键属性ByEntityType=new ConcurrentDictionary();
公共对象[]KeyOf(tenty实体),其中tenty:class
{
Guard.ArgumentNotNull(实体,名称(实体));
var entry=_dbContext.entry(实体);
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();
返回关键部件;
}
公共TKey KeyOf(TEntity实体),其中TEntity:class
{
var keyParts=KeyOf(实体);
如果(keyParts.Length>1)
{
抛出新的InvalidOperationException($“键是复合的,具有{keyParts.Length}”部分。”);
}
返回(TKey)键部件[0];
}
谢谢您的回答。看起来应该能用。我现在不在那个项目上,但我希望在不久的将来能回到这个项目上。我会尽快试用。EF7中是否添加了Context.Model?我正在EF6环境中尝试更改,但由于该属性不存在而中断。是的,这是EntityFrameworkCore v1.1.2中的EF7(Core)属性FindentialType()的签名只接受实体类型名称的字符串。。。Context.Model.FindEntityType(typeof(T).Name).FindPrimaryKey()…似乎与Core 2.1冲突。现在只返回空值。请注意PK是一个影子属性的可能性。var entry=\u dbContext.entry(entity);entry.Metadata.FindPrimaryKey().Properties.Select(p=>entry.Property(p.Name).CurrentValue)代码>