如何解决实体框架:跟踪对独立关联的更改
| 实体框架使跟踪两个实体之间关系的更改变得容易。以下将返回所有已添加和已删除关系的ObjectStateEntry实例:ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Deleted)
.Where(e => e.IsRelationship);
出于审核目的,我想获取有关每个关联端的以下信息:
导航属性名称(如果有)
多重性
对于添加的关联,ObjectStateEntry实例包含关系中涉及的两个实体的EntityKey对象:
var key0 = entry.CurrentValues[0] as EntityKey;
var key1 = entry.CurrentValues[1] as EntityKey;
它还引用表示当前关系的类型:
var relationshipType = objectStateEntry.EntitySet.ElementType;
我想做的是将每个实体键(key0,key1)映射到适当的关联两端(relationshipType.KeyMembers)。据我所知,执行此操作的唯一方法是查看每个关联端的引用类型,并将其与由实体键表示的实体的类型进行匹配。但是,如果关联的两端引用相同的实体类型(请考虑具有经理FK的员工实体引用了另一位员工),则此方法将无效。
因此,这里有到目前为止我获得的导航器名称和关系末端多重性的帮助函数。有没有更好的方法可以做到这一点?
public static string GetNavigationPropertyName(
this ObjectStateEntry entry,EntityKey key)
{
var relationshipType = entry.EntitySet.ElementType;
var entitySet = key.GetEntitySet(
entry.ObjectStateManager.MetadataWorkspace);
var property = entitySet.ElementType.NavigationProperties.Where(
p => p.RelationshipType == relationshipType)
.SingleOrDefault();
if (property == null)
{
return null;
}
return property.Name;
}
public static RelationshipMultiplicity GetAssociationEndMultiplicity(
this ObjectStateEntry entry,EntityKey key)
{
var relationshipType = entry.EntitySet.ElementType;
var entitySet = key.GetEntitySet(
entry.ObjectStateManager.MetadataWorkspace);
foreach (EdmMember member in relationshipType.KeyMembers)
{
var refType = member.TypeUsage.EdmType as RefType;
if (refType.ElementType == entitySet.ElementType)
{
var relEndMember = member as RelationshipEndMember;
return relEndMember.RelationshipMultiplicity;
}
}
throw new InvalidOperationException(
\"couldn\'t find association end\");
}
欢迎任何建议/想法。
谢谢,
丹尼尔
解决方法
与其查看实体键,不如从对象状态条目中提取关联结束。我在Daniel Simmons的博客http://blogs.msdn.com/b/dsimmons/archive/2008/01/17/ef-extension-methods-extravaganza-part-ii-relationship-entry-irelatedend中看到了提示。 aspx。这是我想到的一些扩展方法(UsableValues也来自Daniel的博客):
public static AssociationEndMember[] GetAssociationEnds(
this ObjectStateEntry entry)
{
var fieldMetadata =
entry.UsableValues().DataRecordInfo.FieldMetadata;
return fieldMetadata.Select(
m => m.FieldType as AssociationEndMember).ToArray();
}
public static AssociationEndMember GetOtherAssociationEnd(
this ObjectStateEntry entry,AssociationEndMember end)
{
end.ValidateBelongsTo(entry);
AssociationEndMember[] ends = entry.GetAssociationEnds();
if (ends[0] == end)
{
return ends[1];
}
return ends[0];
}
public static EntityKey GetEndEntityKey(
this ObjectStateEntry entry,AssociationEndMember end)
{
end.ValidateBelongsTo(entry);
AssociationEndMember[] ends = entry.GetAssociationEnds();
if (ends[0] == end)
{
return entry.UsableValues()[0] as EntityKey;
}
return entry.UsableValues()[1] as EntityKey;
}
public static NavigationProperty GetNavigationProperty(
this ObjectStateEntry entry,AssociationEndMember end)
{
end.ValidateBelongsTo(entry);
var otherEnd = entry.GetOtherAssociationEnd(end);
var relationshipType = entry.EntitySet.ElementType;
var key = entry.GetEndEntityKey(end);
var entitySet = key.GetEntitySet(
entry.ObjectStateManager.MetadataWorkspace);
var property = entitySet.ElementType.NavigationProperties.Where(
p => p.RelationshipType == relationshipType &&
p.FromEndMember == end && p.ToEndMember == otherEnd)
.SingleOrDefault();
return property;
}
ValidateBelongsTo扩展方法(UsableValue是Daniel博客中的另一种扩展方法):
static void ValidateBelongsTo(
this AssociationEndMember end,ObjectStateEntry entry)
{
if (!entry.IsRelationship)
{
throw new ArgumentException(\"is not a relationship entry\",\"entry\");
}
var fieldMetadata =
entry.UsableValues().DataRecordInfo.FieldMetadata;
if (fieldMetadata[0].FieldType as AssociationEndMember != end &&
fieldMetadata[1].FieldType as AssociationEndMember != end)
{
throw new InvalidOperationException(string.Format(
\"association end {0} does not participate in the \" +
\"relationship {1}\",end,entry));
}
}
, 选择的答案对我不起作用,可能是因为我正在使用继承。对LeffeBrune的答案的以下修改在Entity Framework 6.1中为我解决了此问题:
public static NavigationProperty GetNavigationProperty(this ObjectStateEntry entry,AssociationEndMember end)
{
end.ValidateBelongsTo(entry);
var otherEnd = entry.GetOtherAssociationEnd(end);
var relationshipType = entry.EntitySet.ElementType;
var entitySet = end.GetEntityType();
var property = entitySet.NavigationProperties
.SingleOrDefault(p => p.RelationshipType == relationshipType &&
p.FromEndMember == end &&
p.ToEndMember == otherEnd);
return property;
}
原始文件的问题在于,从键检索的EntitySet是基类的EntitySet,这意味着NavigationProperties集合不包含子类的任何属性。
我还需要其他一些东西,所以由于花了我很长时间才能完成所有这些工作,因此我将其余内容张贴在这里,以供后代参考:
internal void GetPropertyNames(ObjectContext ctx,ObjectStateEntry entry,out string fromPropName,out string toPropName,out object sourceEntity,out object destEntity)
{
var valueCollection = entry.UsableValues();
EntityKey entityKeyFrom = (EntityKey) valueCollection[1];
EntityKey entityKeyTo = (EntityKey) valueCollection[0];
ObjectStateEntry sourceEntry = ctx.ObjectStateManager.GetObjectStateEntry(entityKeyFrom);
ObjectStateEntry destEntry = ctx.ObjectStateManager.GetObjectStateEntry(entityKeyTo);
sourceEntity = sourceEntry.Entity;
destEntity = destEntry.Entity;
Debug.Assert(sourceEntity != null || destEntity != null,\"Wait,what? One of these MUST exist.\");
AssociationEndMember[] ends = entry.GetAssociationEnds();
Debug.Assert(ends.Length == 2);
NavigationProperty sourceProp = entry.GetNavigationProperty(ends[1]);
NavigationProperty destProp = entry.GetNavigationProperty(ends[0]);
fromPropName = sourceProp.Name;
toPropName = destProp.Name;
if (fromPropName == null && toPropName == null)
{
AssociationSet assoc = (AssociationSet)entry.EntitySet;
AssociationType assocType = (AssociationType)assoc.ElementType;
throw new Exception(String.Format(\"Couldn\'t find at least one property for relationship \\\"{0}\\\"\",assocType.Name));
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。