我有使用EF-CodeFirst 5(.net 4.0上的dll版本4.4.0.0)的应用程序。
我需要能够读取实体元数据,以便对于给定的条目类型,我可以获取以下信息:
哪些属性是一对多关系(引用实体)
哪些属性是多对一关系(引用当前关系的实体的集合)
也很好,但不是绝对必要的:哪些属性是多对多关系(关系的集合)
我可以通过在属性列表上编写foreach循环,然后依靠所有虚拟引用来“识别”它们来获取此信息,但是我觉得这不是“正确”的方式。我知道EdmxWriter
可以xml格式提供该信息,但是它可以通过访问InternalContext来实现,而InternalContext不能公开访问,我想直接获取强类型列表/数组,而不使用该xml。我应该使用哪个API(如果有一个,似乎找不到)?
最佳答案
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});
}
关于ef-code-first - 如何以编程方式读取EF DbContext元数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15718301/