首页 文章

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

提问于
浏览
32

如何找到类的哪个属性是实体框架代码优先实体POCO的主键?

请注意ID /类名“Id”的字符串匹配是一个不好的选择 . 必须有一些方法来挖掘Entity Framework使用的约定并可靠地获取密钥属性 .

提前致谢 .

5 回答

  • 13

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

    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仅适用于您不需要处理映射元数据等详细信息的简单方案 .

  • 55

    万一它可以帮助任何人,我需要能够在事先不知道类型的情况下做到这一点(所以我不能轻易做到 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,但这是我能找到的最好的 .

  • 25

    在EF 6.1中,有一个 Db() 扩展方法可以使这更容易 .

    例:

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

    由于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;
            }
    
  • 9

    与用户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);
    

相关问题