【问题标题】:How I can read EF DbContext metadata programmatically?如何以编程方式读取 EF DbContext 元数据?
【发布时间】:2013-03-21 01:02:23
【问题描述】:

我有使用 EF-CodeFirst 5 的应用程序(dll 版本 4.4.0.0,在 .net 4.0 上)。

我需要能够读取实体元数据,以便针对给定条目类型获取以下信息:

  • 哪些属性是一对多关系(引用实体)
  • 哪些属性是多对一关系(引用当前一个的实体集合)
  • 也不错,但不是绝对必要:哪些属性是多对多关系(关系集合)

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

【问题讨论】:

标签: ef-code-first metadata entity-framework-5


【解决方案1】:

Gorane,这应该让你开始......
(我没怎么玩过——它需要在调试器中进行一些试验才能查看哪些属性/信息以及如何获取它)

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();
}

更具体地说……

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;
    }
}

其中一些属性似乎没有向“公众”公开,因此您需要使用反射 - 或找到一些更聪明的方法 - 但其中包含大量信息。



这些链接中还有更多信息......

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?


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

        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 方法不是我的礼貌,感谢 Jon Skeet,代码是在 this answer 的帮助下创建的

这是我的 CreateLambdaExpression 方法:

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});
}

【讨论】:

  • 谢谢,这让我开始了,我得到了我需要的东西(没有反思),扩展你的答案来展示如何。
  • 太好了,也谢谢你 - 我将把它保留在我的链接中 - 我之前有一些用途 - 但从来没有在太多细节上“详细说明”,这是非常有用的一段代码。一个很好的问题。
  • 似乎 ForeignKeyDependentsForeignKeyPrincipals 在 EF6 的 EntitySet 中标记为 internal
  • @GoranObradovic:CreateLambdaExpression 在这里的作用是什么?如果您只想要NavigationProperties 的过滤列表,是否需要它?如果我能看到你最终得到的表达式树,我就能更好地理解它。您能否再次编辑答案以包含您最终得到的最终CreateLambdaExpression 代码?我还不清楚。谢谢。
  • @InteXX 答案已经链接到另一个答案,该答案给了我该方法,但我包含了我最终使用的简化版本,它只是具有给定名称的属性的选择器。无论如何,尝试使用较新的 EF 版本,这个很烂:)
猜你喜欢
  • 2012-09-06
  • 1970-01-01
  • 2017-09-20
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多