我如何通过编程读取EF DbContext元数据?
我有使用EF-CodeFirst 5(dll版本4.4.0.0,在.net 4.0)的应用程序。
我需要能够读取实体元数据,以便我可以针对给定的条目types获取以下信息:
- 哪些属性是一对多关系(被引用的实体)
- 哪些属性是多对一的关系(引用当前实体的实体的集合)
- 也很好,但不是绝对必要:哪些属性是多 – 很多关系(关系集合)
我可以通过在属性列表中编写foreach循环来获得这些信息,然后依靠所有的引用是虚拟的来“识别”它们,但我觉得这不是“正确”的方式。 我知道EdmxWriter
可以以xml格式提供这些信息,但是通过访问不能公开访问的InternalContext,我想直接获取强types的列表/数组,而不使用该xml。 我应该使用哪个API(如果有这个API,看起来我找不到)?
戈兰,这应该让你开始…
(我没有玩过多less东西 – 在debugging器中试验一下,看看哪些属性/信息以及如何获取它)
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; } }
其中一些属性似乎不会暴露于“普通公众”,所以您需要使用reflection – 或find一些更聪明的方式 – 但是有很多信息在里面。
和一些更多的信息在这些链接…
如何获得EF4中的实体的第一个EntityKey名称
如何提取EF4实体上的属性的数据库表和列名称?
编辑 :使用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,代码是在这个答案的帮助下创build的
这是我的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}); }