如何以编程方式读取EF DbContext元数据? [英] How I can read EF DbContext metadata programmatically?
问题描述
我需要能够读取实体元数据,所以我可以为给定的条目类型获取以下信息:
- 哪些属性是一对多关系(引用的实体)
- 哪些属性是多个关系(实体的集合引用当前的一个)
- 也很好但不是绝对必要:哪些属性是很多关系(集合的关系)
我可以通过在属性列表上写入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;
}
}
其中一些属性似乎不会暴露于一般公众,所以你需要使用反思 - 或找到一些更聪明的方式 - 但很多信息在那里。
这些链接中有更多的信息...
编辑:
使用您的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屋!