如何找到与导航 属性 相关的 ID 属性 或属性?
How can I find the Id property or properties related to a navigational property?
对于我正在使用 Entity Framework 的项目,我希望能够枚举给定对象实例的所有导航属性(假设它是由 EF 生成的对象)。从那里我想为每个导航 属性.
获取相关的 Id 属性
例如,如果我获得 class Person
的实例,我希望能够找到它的导航属性 Address
和 Boss
。对于这两个导航属性,我想 "lookup" 相关的 Id 属性称为 AddressId
和 BossId
.
我需要这些 Id 属性,这样我就可以 运行 在不同的数据库上查询,该数据库没有相同的外键但具有完全相同的 ID。
到目前为止,我已经想出了一种方法来为 EF 生成的随机对象实例获取 RelationshipManager。在调试时,我可以通过 Manager 的 Relationships
属性 获取外键关系。但我只能得到导航 属性 名称。所以我可以看到有一个 FK_Person_Address
与名为 Address
的导航 属性 有关,但我找不到 AddressId
.
所以我的问题是,我如何动态地(不知道 Person
class' 布局)发现 AddressId
属性 与 Address
?
我知道外键关系可能在关系的另一端有 ID 属性(Boss
指向 Person
而不是 Person
一个 BossId
)。在那种情况下,我仍然想在检查 Person
.
的实例时发现 Boss
有一个 PersonId
这里有一个方法可以returns知道实体对象的键值:
IEnumerable<IDictionary<string,object>> GetKeyValues<T>(DbContext db,
IEnumerable<T> 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
包含实体的键值作为键值对。 (具有复合键的实体具有多个键值。)
这将为您提供一个字典,其中所有导航属性作为键,所有相关属性作为值(值可能是来自其他实体的 属性)
将这些添加到您的 DBContext class 并调用 db.GetForeignKeyProperties<Person>()
结果将类似于:
"Address" - "AddressID"
"Boss" - "Person.BossID"
public Dictionary<string,string> GetForeignKeyProperties<DBType>()
{
EntityType table = GetTableEntityType<DBType>();
Dictionary<string, string> foreignKeys = new Dictionary<string, string>();
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<DBType>()
{
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<EntityType>(DBType.FullName, DataSpace.OSpace)) as EntityType;
return table;
}
对于我正在使用 Entity Framework 的项目,我希望能够枚举给定对象实例的所有导航属性(假设它是由 EF 生成的对象)。从那里我想为每个导航 属性.
获取相关的 Id 属性例如,如果我获得 class Person
的实例,我希望能够找到它的导航属性 Address
和 Boss
。对于这两个导航属性,我想 "lookup" 相关的 Id 属性称为 AddressId
和 BossId
.
我需要这些 Id 属性,这样我就可以 运行 在不同的数据库上查询,该数据库没有相同的外键但具有完全相同的 ID。
到目前为止,我已经想出了一种方法来为 EF 生成的随机对象实例获取 RelationshipManager。在调试时,我可以通过 Manager 的 Relationships
属性 获取外键关系。但我只能得到导航 属性 名称。所以我可以看到有一个 FK_Person_Address
与名为 Address
的导航 属性 有关,但我找不到 AddressId
.
所以我的问题是,我如何动态地(不知道 Person
class' 布局)发现 AddressId
属性 与 Address
?
我知道外键关系可能在关系的另一端有 ID 属性(Boss
指向 Person
而不是 Person
一个 BossId
)。在那种情况下,我仍然想在检查 Person
.
Boss
有一个 PersonId
这里有一个方法可以returns知道实体对象的键值:
IEnumerable<IDictionary<string,object>> GetKeyValues<T>(DbContext db,
IEnumerable<T> 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
包含实体的键值作为键值对。 (具有复合键的实体具有多个键值。)
这将为您提供一个字典,其中所有导航属性作为键,所有相关属性作为值(值可能是来自其他实体的 属性)
将这些添加到您的 DBContext class 并调用 db.GetForeignKeyProperties<Person>()
结果将类似于:
"Address" - "AddressID"
"Boss" - "Person.BossID"
public Dictionary<string,string> GetForeignKeyProperties<DBType>()
{
EntityType table = GetTableEntityType<DBType>();
Dictionary<string, string> foreignKeys = new Dictionary<string, string>();
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<DBType>()
{
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<EntityType>(DBType.FullName, DataSpace.OSpace)) as EntityType;
return table;
}