我发现this answer(除非我遗漏了某些内容)提供了一个很好的解决方案来捕获对DbContext中所有独立关联所做的所有更改。我正在尝试将该解决方案调整为更具体的内容,以创建可以在特定实体上查找特定导航属性的更改的函数。目标是让这个函数的用户不必担心EntityFramework的任何内部,而只关心他的POCO模型。
这是我到目前为止所做的,并且它有效。但在我看来,如果实体框架的内部实现细节发生变化,它看起来非常混乱并容易中断 - 特别是那里有一个“魔术字符串”"ClrPropertyInfo"
,可能不是EF接口合同的一部分。 / p>
public partial class EntityFrameworkMaterializer
{
public IEnumerable<T2> GetAssociationChanges<T1,T2>(T1 parent, string propertyName, EntityState findState)
{
// this.context is a DbContext instance that is a property of the object.
ObjectContext ocontext = ((IObjectContextAdapter)this.context).ObjectContext;
MetadataWorkspace metadataWorkspace = ocontext.MetadataWorkspace;
// Find the AssociationType that matches the property traits given as input
AssociationType atype =
metadataWorkspace.GetItems<AssociationType>(DataSpace.CSpace)
.Where(a => a.AssociationEndMembers.Any(
ae => ae.MetadataProperties.Any(mp => mp.Name == "ClrPropertyInfo" // Magic string!!!
&& ((PropertyInfo)mp.Value).Name == propertyName
&& typeof(T1).IsAssignableFrom(((PropertyInfo)mp.Value).DeclaringType)
)
)
).First();
// Find added or deleted DbDataRecords from the above discovered type
ocontext.DetectChanges();
IEnumerable<DbDataRecord> dbDataRecords = ocontext.ObjectStateManager
.GetObjectStateEntries(findState)
.Where(e => e.IsRelationship)
// Oddly, this works, while doing the same thing below requires comparing .Name...?
.Where(e => e.EntitySet.ElementType == atype)
.Select(e => findState == EntityState.Deleted ? e.OriginalValues : e.CurrentValues);
// Get the actual entities using the EntityKeys in the DbDataRecord
IList<T2> relationChanges = new List<T2>();
foreach (System.Data.Common.DbDataRecord ddr in dbDataRecords)
{
EntityKey ek = (EntityKey)ddr[0];
// Comparing .ElementType to atype doesn't work, see above...?
if (!(ek.GetEntitySet(metadataWorkspace).ElementType.Name == atype.Name))
{
ek = (EntityKey)ddr[1];
}
relationChanges.Add((T2)ocontext.GetObjectByKey(ek));
}
return relationChanges;
}
}
使用示例:
// Student <--> Course is many-to-many Independent Association
IEnumerable<Course> droppedCourses;
droppedCourses = GetAssociationChanges<Student, Course>(
student,
"EnrolledCourses",
EntityState.Deleted
);
这是在调试器中进行大量逆向工程和挖掘对象的结果。除了魔术字符串问题之外,我想知道是否有更直接的途径来根据“结束”实体类型和导航属性名称来确定代表IAs的“关系条目”的类型。