给定一个实体,我想以通用方式检索相关实体的主键。 例如:对于客户,我想要一份其订单ID的列表。
我尝试的当前签名:
GetPrimaryKeysOfRelatedEntities(DbContext db, object entity)
我能够检索实体的PK,并且我能够检索实体的导航属性......但我无法获得实体导航属性的PK。
我在这里错过了一个小链接!
这是获取实体密钥的代码,它不适用于导航属性
private static IEnumerable<string> GetEntityType(DbContext db, Type entityType)
{
entityType = ObjectContext.GetObjectType(entityType);
var metadataWorkspace = ((IObjectContextAdapter)db).ObjectContext.MetadataWorkspace;
var objectItemCollection = (ObjectItemCollection)metadataWorkspace.GetItemCollection(DataSpace.OSpace);
ReadOnlyCollection<EntityType> entityTypes = metadataWorkspace.GetItems<EntityType>(DataSpace.OSpace);
if (entityTypes == null)
{
throw new InvalidOperationException();
}
var ospaceType = entityTypes.SingleOrDefault(t => objectItemCollection.GetClrType(t) == entityType);
if (ospaceType == null)
{
throw new ArgumentException(
string.Format("The type '{0}' is not mapped as an entity type.", entityType.Name), "entityType");
}
return ospaceType.KeyMembers.Select(k => k.Name);
}
此代码使用EntityType,我应该使用其他东西,但我不确定是什么。
答案 0 :(得分:1)
我看不出问题,你有一段很棒的代码可以按类型获取实体的主键。
您可以使用反射来枚举实体类型的属性,并为这些属性的类型调用代码。就像这样:
var entityType = entity.GetType(); // or another type source
foreach (var prop in type.GetProperties())
{
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericArguments().Any(x => x.Assembly == type.Assembly))
{
var navPropType = prop.PropertyType.GetGenericArguments().First(x => x.Assembly == type.Assembly);
var keysForThisNavPropType = GetEntityType(db, navPropType);
}
else if (prop.PropertyType.Assembly == type.Assembly)
{
var keysForThisNavPropType = GetEntityType(db, prop.PropertyType);
}
}
正如您所看到的,查找导航属性的条件是其包含的assambly与您的主要类型相同。
修改强>
好的,试试这个:
// we need DbContext vaule
var db = YOUR_DB_CONTEXT; // assing db context here
// So we can get ObjectContext instance
var ctx = ((IObjectContextAdapter) db).ObjectContext;
// we need some entity to check
object entity = someYourEntity; // assign your entity here
// let's get its type
var type = entity.GetType();
// helper function to get set name
Func<Type, ObjectContext, string> getEntitySetByObjectType = (t, context) =>
{
var container =
context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
var entitySet =
container.BaseEntitySets.First(item => item.ElementType.Name.Equals(t.Name));
return container.Name + "." + entitySet.Name;
};
// go through the entity's properties
foreach (var prop in type.GetProperties())
{
// nav properties which are collections
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericArguments().Any(x => x.Assembly == type.Assembly))
{
var val = (IEnumerable)prop.GetValue(entity);
if (val != null)
{
// get value and check if it is not null
string setName = null;
// go through collection values
foreach (var obj in val)
{
if (setName == null)
setName = getEntitySetByObjectType(obj.GetType(), ctx);
// get primary key values
var entityKey = ctx.CreateEntityKey(setName, obj);
Console.WriteLine(entityKey);
}
}
}
// nav props which are single objects
else if (prop.PropertyType.Assembly == type.Assembly)
{
// get value and check if it is not null
var val = prop.GetValue(entity);
if (val != null)
{
// get primary key values
var entityKey = ctx.CreateEntityKey(getEntitySetByObjectType(prop.PropertyType, ctx), val);
Console.WriteLine(entityKey);
}
}
}
CreateEntityKey方法返回EntityKey类(http://msdn.microsoft.com/ru-ru/library/system.data.entitykey(v=vs.110).aspx)的对象,该类具有EntityKeyValues属性,该属性是EntityKeyMember的数组。 EntityKeyMember具有属性Key和Value,它们是主键名和值。