C# 有没有比这更好/更干净的方法来查找独立关联更改(添加/删除)?
我发现它(除非我遗漏了什么)提供了一个很好的解决方案,可以捕获对DbContext中所有独立关联所做的所有更改。我正试图使该解决方案适应更具体的情况,以创建一个函数,该函数可以查找特定实体上特定导航属性的更改。目标是让此函数的用户不必担心EntityFramework的任何内部内容,只需关心其POCO模型 这就是我到目前为止所做的,而且是有效的。但在我看来,如果实体框架的内部实现细节发生变化,它看起来非常混乱,并且容易崩溃——特别是其中有一个“神奇字符串”C# 有没有比这更好/更干净的方法来查找独立关联更改(添加/删除)?,c#,entity-framework,many-to-many,entity-framework-6,C#,Entity Framework,Many To Many,Entity Framework 6,我发现它(除非我遗漏了什么)提供了一个很好的解决方案,可以捕获对DbContext中所有独立关联所做的所有更改。我正试图使该解决方案适应更具体的情况,以创建一个函数,该函数可以查找特定实体上特定导航属性的更改。目标是让此函数的用户不必担心EntityFramework的任何内部内容,只需关心其POCO模型 这就是我到目前为止所做的,而且是有效的。但在我看来,如果实体框架的内部实现细节发生变化,它看起来非常混乱,并且容易崩溃——特别是其中有一个“神奇字符串”“ClrPropertyInfo”,可能
“ClrPropertyInfo”
,可能不是EF接口契约的一部分
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;
}
}
公共部分类EntityFrameworkMaterializer
{
公共IEnumerable GetAssociationChanges(T1父级、字符串属性名称、EntityState findState)
{
//this.context是作为对象属性的DbContext实例。
ObjectContext ocontext=((IOObjectContextAdapter)this.context).ObjectContext;
MetadataWorkspace MetadataWorkspace=ocontext.MetadataWorkspace;
//查找与作为输入提供的属性特征匹配的AssociationType
关联类型=
metadataWorkspace.GetItems(DataSpace.CSpace)
.其中(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();
//从上述发现的类型中查找添加或删除的DbDataRecords
ocontext.DetectChanges();
IEnumerable dbDataRecords=ocontext.ObjectStateManager
.GetObjectStateEntries(findState)
.其中(e=>e.IsRelationship)
//奇怪的是,这是可行的,而做下面同样的事情需要比较。名称。。。?
.其中(e=>e.EntitySet.ElementType==atype)
.选择(e=>findState==EntityState.Deleted?e.OriginalValues:e.CurrentValues);
//使用DbDataRecord中的EntityKeys获取实际实体
IList relationChanges=新列表();
foreach(dbDataRecords中的System.Data.Common.DbDataRecord ddr)
{
EntityKey ek=(EntityKey)ddr[0];
//将.ElementType与atype进行比较不起作用,请参见上文。。。?
if(!(ek.GetEntitySet(metadataWorkspace.ElementType.Name==atype.Name))
{
ek=(EntityKey)ddr[1];
}
添加((T2)ocontext.GetObjectByKey(ek));
}
回归关系变化;
}
}
用法示例:
// Student <--> Course is many-to-many Independent Association
IEnumerable<Course> droppedCourses;
droppedCourses = GetAssociationChanges<Student, Course>(
student,
"EnrolledCourses",
EntityState.Deleted
);
//学生课程是多对多的独立关联
i数不清的辍学课程;
droppedCourses=GetAssociationChanges(
学生,
“注册课程”,
EntityState。已删除
);
这是大量逆向工程和在调试器中挖掘对象的结果。除了魔法字符串问题,我想知道是否有更直接的方法根据“结束”实体类型和导航属性名称来确定代表IAs的“关系条目”的类型。我不知道您为什么要冒险进入这个领域,但如果是为了保存断开连接的实体,也许您可以查看GraphDiff。无论如何,这段代码还是值得一看的。@GertArnold非常有趣,谢谢……不完全是我在做的,但类似于此——我会记住GraphDiff。在我的例子中,我正在重新连接并协调一个反序列化的对象图,是的。但这段代码用于将这些更改协调到上下文和实际调用
.SaveChanges()
——因为EF已经完成了所有更改跟踪,所以此方法捕获提交之前所做的更改。在我当前的用例中,我使用它来记录关于所做更改的消息,类似于审计日志,这是我在其他地方看到的此类操作。