如何以编程方式读取EF DbContext元数据? [英] How I can read EF DbContext metadata programmatically?

查看:277
本文介绍了如何以编程方式读取EF DbContext元数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有应用程序使用EF-CodeFirst 5(dll ver 4.4.0.0,on .net 4.0)。



我需要能够读取实体元数据,所以我可以为给定的条目类型获取以下信息:




  • 哪些属性是一对多关系(引用的实体)

  • 哪些属性是多个关系(实体的集合引用当前的一个)

  • 也很好但不是绝对必要:哪些属性是很多关系(集合的关系)



我可以通过在属性列表上写入foreach循环来获取此信息,然后依靠所有引用是虚拟的,但我觉得这不是正确的方式。我知道, EdmxWriter 可以以xml格式提供信息,但是通过访问不可公开访问的InternalContext来实现,我想直接获得强类型列表/数组,没有使用该xml。我应该使用哪个API(如果有一个这样,似乎我找不到)?

解决方案

Gorane,this应该让你开始...

(我没有玩得太多 - 调试器需要一些实验来查看哪些属性/信息以及如何获取)

  using(var db = new MyDbContext())
{
var objectContext =((IObjectContextAdapter)db).ObjectContext;
var container = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName,DataSpace.CSpace);
foreach(var set in container.BaseEntitySets)
{
// set.ElementType。
foreach(set.MetadataProperties中的var metaproperty)
{
// metaproperty。
}
}

// ...或...

var keyName = objectContext
.MetadataWorkspace
。 GetEntityContainer(objectContext.DefaultContainerName,DataSpace.CSpace)
.BaseEntitySets
.First(meta => meta.ElementType.Name ==Question)
.ElementType
.KeyMembers
.Select(k => k.Name)
.FirstOrDefault();
}

,更具体地说...

  foreach(var set in container.BaseEntitySets)
{
var dependents =((EntitySet)(set))ForeignKeyDependents;
var principals =((EntitySet)(set))。ForeignKeyPrincipals;
var navigationProperties =((EntityType)(set.ElementType))。NavigationProperties;
foreach(nav nav in navigationProperties)
{
// nav.RelationshipType;
}
}

其中一些属性似乎不会暴露于一般公众,所以你需要使用反思 - 或找到一些更聪明的方式 - 但很多信息在那里。









这些链接中有更多的信息.​​..



如何获取EF4中实体的EntityKey名称



如何提取EF4上属性的数据库表和列名称实体?






编辑
使用您的navigationProperties列表作为起点,我得到了我需要的一切,如下所示:

  ManyToManyReferences = navigationProperties.Where(np => 
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many&&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Select(np => E xtensions.CreateLambdaExpression< TEntity>(np.Name))
.ToList();

OneToManyReferences = navigationProperties.Where(np =>
(np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One ||
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne) &
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Select(np => Extensions.CreateLambdaExpression< TEntity>(np.Name))
.ToList() ;

ManyToOneReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many&&$&
(np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity。一个||
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne))
.Select(np => Extensions.CreateLambdaExpression< TEntity>(np.Name))
.ToList() ;

OneToOneReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One&&$&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One )
.Select(np => Extensions.CreateLambdaExpression< TEntity>(np.Name))
.ToList();

CreateLambdaExpression方法不是我的礼貌,信用转到Jon Skeet,代码是在这个答案



这是我的CreateLambdaExpression方法:

  public static Expression< Func< TEntity,object>> CreateLambdaExpression< TEntity>(string propertyName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TEntity),typeof(TEntity).Name);
表达式属性= Expression.Property(parameter,propertyName);

返回Expression.Lambda< Func< TEntity,object>>(property,new [] {parameter});
}


I have application which uses EF-CodeFirst 5 (dll ver 4.4.0.0, on .net 4.0).

I need to be able to read entity metadata, so that I can, for a given entry type get following information:

  • which properties are one-many relations (referenced entities)
  • which properties are many-one relations (collections of entities referencing current one)
  • also nice but not absolutely necessary: which properties are many-many relations (collections of relations)

I can get this info by writing foreach loops on lists of properties and then "recognizing" them by relying on all of the references being virtual, but I feel that is not "proper" way. I know that EdmxWriter can provide that information in xml format, but it does so by accessing InternalContext which is not publicly accessible and I want to get strongly typed lists/arrays directly, without using that xml. Which API should I use (if there is one for this, it seems that I cannot find it)?

解决方案

Gorane, this should get you started...
(I haven't played much with it - it takes a bit of experimenting in the debugger to see which properties / info and how to get it)

using (var db = new MyDbContext())
{
    var objectContext = ((IObjectContextAdapter)db).ObjectContext;
    var container = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace);
    foreach (var set in container.BaseEntitySets)
    {
        // set.ElementType.
        foreach (var metaproperty in set.MetadataProperties)
        {
            // metaproperty.
        }
    }

    // ...or... 

    var keyName = objectContext
        .MetadataWorkspace
        .GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace)
        .BaseEntitySets
        .First(meta => meta.ElementType.Name == "Question")
        .ElementType
        .KeyMembers
        .Select(k => k.Name)
        .FirstOrDefault();
}

and more specifically...

foreach (var set in container.BaseEntitySets)
{
    var dependents = ((EntitySet)(set)).ForeignKeyDependents;
    var principals = ((EntitySet)(set)).ForeignKeyPrincipals;
    var navigationProperties = ((EntityType)(set.ElementType)).NavigationProperties;
    foreach (var nav in navigationProperties)
    {
        // nav.RelationshipType;
    }
}

Some of these properties seem to not be exposed to 'general public' so you'd need to use reflection - or find some smarter way - but a good deal of info is in there.



And some more info in these links...

How to get first EntityKey Name for an Entity in EF4

How can I extract the database table and column name for a property on an EF4 entity?


EDIT: Using your list of navigationProperties as starting point, I got everything I needed like this:

        ManyToManyReferences = navigationProperties.Where(np =>
            np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
            np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
            .Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
            .ToList();

        OneToManyReferences = navigationProperties.Where(np =>
            (np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One ||
            np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne) &&
            np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
            .Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
            .ToList();

        ManyToOneReferences = navigationProperties.Where(np =>
            np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
            (np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One ||
            np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne))
            .Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
            .ToList();

        OneToOneReferences = navigationProperties.Where(np =>
            np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One &&
            np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One)
            .Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
            .ToList();

CreateLambdaExpression method is not my courtesy, credits go to Jon Skeet, code was created with help of this answer

Here is my CreateLambdaExpression method:

public static Expression<Func<TEntity, object>> CreateLambdaExpression<TEntity>(string propertyName)
{
    ParameterExpression parameter = Expression.Parameter(typeof (TEntity), typeof (TEntity).Name);
    Expression property = Expression.Property(parameter, propertyName);

    return Expression.Lambda<Func<TEntity, object>>(property, new[] {parameter});
}

这篇关于如何以编程方式读取EF DbContext元数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆