使用序列化在实体框架中的两个ObjectContexts之间复制实体

时间:2012-09-26 14:55:08

标签: c# .net entity-framework serialization xml-serialization

前言

我知道这可能已被视为crazy question,但我正在寻找有关如何继续复制所有的最受过教育的建议和经过验证的建议从ObjectContext到在不同商店中备份的新创建的ObjectContext的数据(即所有实体和关系)。 请参阅"Cloning" EntityConnections and ObjectContexts in Entity Framework,了解我是如何设置的。


简介

我见过Cloning data on Entity Framework,但是:

  1. 我正在寻找整个enchilada ,即整个对象图:所有实体&关系。稍后,我将对对象图的哪些部分进行更精细的选择)

  2. 根据我在下面的更新,我没有使序列化工作,但仅限于特殊情况。我觉得它真的是一个不那么复杂的任务,但它却出人意料地具有挑战性。我肯定需要了解如何使其发挥作用。


  3. 第1步

    好的,这是我到目前为止所尝试过的。

    我知道当我使用Detach / Attach幂二人时,关系是kaput- ,我实际上想要保留整个对象图。

    因此,我考虑使用MergeOption.NoTracking选项加载根实体:

    var serializer = new DataContractSerializer(typeof(Root));
    
    var query = (ObjectQuery<Root>) sourceContext.Roots
        .Include(d => d.Children.Select(c => c.MoreChildren.Select(r => r.EvenMoreChildren)))
        .Include(d => d.Children.Select(c => c.MoreChildren.Select(r => r.MoreAndMoreChildren)))
        .Include(d => d.Children.Select(c => c.MoreChildren.Select(r => r.Shizzle)));
    
    foreach (var d in query.Execute(MergeOption.NoTracking)) {
        //sourceContext.Detach(d); // not needed
        Print(d);
        using (var ios = new MemoryStream()) {
            serializer.WriteObject(ios, d);
            ios.Seek(0, SeekOrigin.Begin);
            var dd = (Root) serializer.ReadObject(ios);
            //Console.WriteLine(string.Join(",", dd.EntityKey.EntityKeyValues.Select(k => k.Key + "=" + k.Value)));
            targetContext.Roots.AddObject(dd);
        }
    }
    

    鉴于我正在将实体加载为非跟踪,我不再需要调用sourceContext.Detach(d)

    Print方法只是打印子对象树,它表明到目前为止事情进展顺利(我不会在这里显示它因为它是巨大且不相关的)。

    然而,现在整个事情正在吹嘘@ serializer.WriteObject(ios, d),并带有以下信息:

    “当返回带有NoTracking合并选项的对象时,只有在EntityCollectionEntityReference不包含对象时才能调用加载。”

    (哪种方式有意义,因为序列化程序可能正在尝试延迟加载相关实体。)

    请记住,如果我不使用NoTracking,我必须分离实体,但之后我会失去我的关系......


    第2步

    当然我在执行序列化循环之前尝试设置sourceContext.ContextOptions.LazyLoadingEnabled = false,并修复了上面的错误,但这导致臭名昭着:

    “无法添加或附加该对象,因为其EntityReference的{​​{1}}属性值与此对象的EntityKey不匹配。”

    另外,请记住,我仍然无法取消注释EntityKey,因为我用sourceContext.Detach(d)加载了根...


    第3步

    我已经尝试在序列化之前设置NoTracking,甚至在克隆实体上反序列化之后......都无济于事:

    EntityKey = null

    可疑的是,我甚至不知道上面讨论的血腥“对象”是什么。

    我尝试使用纯粹的EF方法来解决这个问题,我真的,真的,真的,真的很难过吗?

    我完全被诅咒了吗?!?!?! :(

1 个答案:

答案 0 :(得分:5)

@khovanskiiªn - 这就是事情。尽管你对EF的精彩表达了什么,但它并不是为了做到这一点而设计的。你整天都可以对锤子的奇迹充满诗意,但如果你的问题需要扳手,它对你没有帮助。

有很多解决方案可以满足您的需求,但不要使用EF并在SQL端执行,它甚至有一个奇特的名称。它被称为ETL或Extract / Transform / Load,它的唯一目的是从一组表中获取数据并将其移动到另一组,可能在两者之间按摩数据。

事实上,您可以无缝地将这些工具与客户端代码集成。例如,可以从客户端代码执行SSIS包,并将参数传递给它以控制处理哪些数据。

事实上,实体框架旨在使用单个上下文,并且它仅跟踪单个上下文中的关系和更改。一旦你将它分开,它就会丢失这些信息。

更重要的是,实体框架对于这种事情来说是极其低效的,因为EF适用于单个实体,而不是批量/批量操作。如果你有100万条记录,可能需要一整天才能完成一次操作,而sql端批处理操作可能需要几分钟。

帮自己一个忙,查看SSIS(Sql Server Integration Services)。