如何找到与导航属性相关的Id属性?
对于我正在使用Entity Framework的项目,我希望能够枚举给定对象实例的所有导航属性(假设它是由EF生成的对象)。 从那里我想获得每个导航属性的相关Id属性。
例如,如果我得到Person
类的实例,我希望能够找到它的名为Address
and Boss
的导航属性。 对于那两个导航属性,我想“查找”名为AddressId
和BossId
的相关Id属性。
我需要那些Id属性,所以我可以在不同的数据库上运行查询,该数据库没有相同的外键但具有完全相同的ID。
到目前为止,我已经想出了一种方法来获取由EF生成的随机对象实例的RelationshipManager 。 在调试时,我可以通过Manager的Relationships
属性获取外键关系。 但我只能获得导航属性名称。 所以我可以看到有一个FK_Person_Address
与名为Address
的导航属性相关,但我找不到AddressId
。
所以我的问题是,我如何动态地(不知道Person
类的布局)发现与Address
相关的AddressId
属性?
我知道外键关系可能在关系的另一端有Id属性( Boss
指向Person
而不是Person
有BossId
)。 在那种情况下,当我正在检查一个Person
实例时,我仍然想发现Boss
有一个PersonId
。
这将为您提供一个字典,其中所有导航属性为Key,所有相关属性为Value(该值可能是其他实体的属性)
将这些添加到您的DBContext类并调用db.GetForeignKeyProperties
结果将是这样的:
“地址” – “地址ID”
“老板” – “Person.BossID”
public Dictionary GetForeignKeyProperties() { EntityType table = GetTableEntityType (); Dictionary foreignKeys = new Dictionary(); foreach (NavigationProperty np in table.NavigationProperties) { var association = (np.ToEndMember.DeclaringType as AssociationType); var constraint = association.ReferentialConstraints.FirstOrDefault(); if (constraint != null && constraint.ToRole.GetEntityType() == table) foreignKeys.Add(np.Name, constraint.ToProperties.First().Name); if (constraint != null && constraint.FromRole.GetEntityType() == table) foreignKeys.Add(np.Name, constraint.ToProperties.First().DeclaringType.Name+"."+constraint.ToProperties.First().Name); } return foreignKeys; } private EntityType GetTableEntityType () { return GetTableEntityType(typeof(DBType)); } private EntityType GetTableEntityType(Type DBType) { ObjectContext objContext = ((IObjectContextAdapter)this).ObjectContext; MetadataWorkspace workspace = objContext.MetadataWorkspace; EntityType table = workspace.GetEdmSpaceType((StructuralType)workspace.GetItem(DBType.FullName, DataSpace.OSpace)) as EntityType; return table; }
这是一个返回已知实体对象的键值的方法:
IEnumerable> GetKeyValues(DbContext db, IEnumerable entities) where T : class { var oc = ((IObjectContextAdapter)db).ObjectContext; return entities.Select (e => oc.ObjectStateManager.GetObjectStateEntry(e)) .Select(objectStateEntry => objectStateEntry.EntityKey) .Select(ek => ek.EntityKeyValues .ToDictionary (x => x.Key, y => y.Value)); }
此方法使用基础ObjectContext
API来获取属于每个实体对象的ObjectStateEntry
对象。 EntityKey
包含实体的键值作为键值对。 (具有复合键的实体具有多个键值。)