Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有比这更好/更干净的方法来查找独立关联更改(添加/删除)?_C#_Entity Framework_Many To Many_Entity Framework 6 - Fatal编程技术网

C# 有没有比这更好/更干净的方法来查找独立关联更改(添加/删除)?

C# 有没有比这更好/更干净的方法来查找独立关联更改(添加/删除)?,c#,entity-framework,many-to-many,entity-framework-6,C#,Entity Framework,Many To Many,Entity Framework 6,我发现它(除非我遗漏了什么)提供了一个很好的解决方案,可以捕获对DbContext中所有独立关联所做的所有更改。我正试图使该解决方案适应更具体的情况,以创建一个函数,该函数可以查找特定实体上特定导航属性的更改。目标是让此函数的用户不必担心EntityFramework的任何内部内容,只需关心其POCO模型 这就是我到目前为止所做的,而且是有效的。但在我看来,如果实体框架的内部实现细节发生变化,它看起来非常混乱,并且容易崩溃——特别是其中有一个“神奇字符串”“ClrPropertyInfo”,可能

我发现它(除非我遗漏了什么)提供了一个很好的解决方案,可以捕获对DbContext中所有独立关联所做的所有更改。我正试图使该解决方案适应更具体的情况,以创建一个函数,该函数可以查找特定实体上特定导航属性的更改。目标是让此函数的用户不必担心EntityFramework的任何内部内容,只需关心其POCO模型

这就是我到目前为止所做的,而且是有效的。但在我看来,如果实体框架的内部实现细节发生变化,它看起来非常混乱,并且容易崩溃——特别是其中有一个“神奇字符串”
“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已经完成了所有更改跟踪,所以此方法捕获提交之前所做的更改。在我当前的用例中,我使用它来记录关于所做更改的消息,类似于审计日志,这是我在其他地方看到的此类操作。