首先是实体框架代码。查找主键

问题描述 投票:0回答:5

如何找到类的哪个属性是实体框架 Code First 实体 POCO 的主键?

请注意,Id /类名+“Id”的字符串匹配是一个不好的选择。必须有某种方法来挖掘实体框架使用的约定并可靠地获取关键属性。

提前致谢。

entity-framework-4.1 ef-code-first
5个回答
63
投票

您可以要求映射元数据来获取关键属性的名称(可以有多个):

ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectSet<YourEntity> set = objectContext.CreateObjectSet<YourEntity>();
IEnumerable<string> keyNames = set.EntitySet.ElementType
                                            .KeyMembers
                                            .Select(k => k.Name);

一旦有了键名称,您就可以使用反射来访问它们的值。

正如您所看到的,该方法恢复为 ObjectContext API,因为 DbContext API 仅适用于简单的场景,您无需担心映射元数据等细节。


28
投票

如果它对任何人有帮助,我需要能够在事先不知道类型的情况下做到这一点(所以我不能轻易做到

CreateObjectSet<YourEntity>()
,因为我不知道
YourEntity
),所以我能够适应@ Ladislav 的解决方案如下:

// variable "type" is a System.Type passed in as a method parameter
ObjectContext objectContext = ((IObjectContextAdapter)this.context).ObjectContext;
IEnumerable<string> retval = (IEnumerable<string>)objectContext.MetadataWorkspace
    .GetType(type.Name, type.Namespace, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace)
    .MetadataProperties
    .Where(mp => mp.Name == "KeyMembers")
    .First()
    .Value;

看起来有点奇怪,

MetadataWorkspace.GetType
需要类型名称和命名空间的字符串而不是System.Type,但这是我能找到的最好的。


14
投票

在 EF 6.1 中,有一个

Db()
扩展方法可以使这变得更容易。

示例:

public static IEnumerable<string> GetPrimaryKeyPropertyNames(DbContext db, Type entityType)
{
    return db.Db(entityType).Pks.Select(x => x.PropertyName);
}

9
投票
由于 Table Per Type 继承,我对上述两种方法都遇到了问题。我的工作版本(基于@S'pht'Kr的解决方案,但由于这个原因使用DataSpace.OSpace而不是DataSpace.CSpace)如下:

protected IEnumerable<string> GetKeyPropertyNames() { var objectContext = ((System.Data.Entity.Infrastructure.IObjectContextAdapter) this.Context).ObjectContext; return GetKeyPropertyNames(typeof (TEntity), objectContext.MetadataWorkspace); } private static IEnumerable<string> GetKeyPropertyNames(Type type, MetadataWorkspace workspace) { EdmType edmType; if (workspace.TryGetType(type.Name, type.Namespace, DataSpace.OSpace, out edmType)) { return edmType.MetadataProperties.Where(mp => mp.Name == "KeyMembers") .SelectMany(mp => mp.Value as ReadOnlyMetadataCollection<EdmMember>) .OfType<EdmProperty>().Select(edmProperty => edmProperty.Name); } return null; }
    

4
投票
像用户 rashleighp 一样,我也想要用户 Ladislav Mrnka 答案的变体,只需要在运行时知道类型,而不需要在编译时知道类型。 与用户 rashleighp 一样,用户 S'pht'Kr 的解决方案对我不起作用,但他的解决方案确实有效。 下面,我通过提供对我有用的他的答案的简单版本来为这次对话做出贡献。 然而,我刚刚了解到用户 anjdreas 的解决方案,这就是我将使用的解决方案。

// variable "type" is a System.Type passed in as a method parameter ((IObjectContextAdapter)context) .ObjectContext .MetadataWorkspace .GetItem<EntityType>(type.FullName, DataSpace.OSpace) .KeyProperties .Select(p => p.Name);
    
© www.soinside.com 2019 - 2024. All rights reserved.