3

前言

我知道这可能已经被认为是一个疯狂的问题,但我正在寻找有关如何继续将所有数据(即所有实体和关系)从一个复制到新创建的支持的最受过教育的建议和经过验证的建议。 . 请参阅实体框架中的“克隆”EntityConnections 和 ObjectContexts 以了解我是如何设置它的。ObjectContextObjectContext


介绍

在 Entity Framework 上看到了 Cloning data但是:

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

  2. 根据我下面的更新,我没有使序列化工作,但仅在特殊情况下。我觉得这真的是一个不那么复杂的任务,但它具有惊人的挑战性。我绝对需要一些关于如何使它工作的见解。


步骤1

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

我知道,当我使用Detach/ Attachpower duo 时,关系是有限的——<strong>我实际上想要保留整个对象图。

因此,我正在考虑使用以下选项加载根实体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时才能调用 Load 。”EntityCollectionEntityReference

(这有点道理,因为序列化程序可能正在尝试延迟加载相关实体。)

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


第2步

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

“无法添加或附加该对象,因为它EntityReferenceEntityKey属性值与该对象的不匹配EntityKey。”

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


第 3 步

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

sourceContext.ContextOptions.LazyLoadingEnabled = false;

foreach (var d in query.Execute(MergeOption.NoTracking)) {
    //sourceContext.Detach(d);
    Print(d);
    d.EntityKey = null;
    using (var ios = new MemoryStream()) {
        serializer.WriteObject(ios, d);
        ios.Seek(0, SeekOrigin.Begin);
        var dd = (Root) serializer.ReadObject(ios);
        if (dd.EntityKey != null) {
            Console.WriteLine("Deserialized EntityKey: {0}", string.Join(",", dd.EntityKey.EntityKeyValues.Select(k => k.Key + "=" + k.Value)));
            dd.EntityKey = null;
        }
        targetContext.Roots.AddObject(dd);
    }
}

可疑的是,我什至不知道上面所说的例外是什么该死的“对象”。

我真的,真的,真的,真的注定要尝试用纯粹的 EF 方法来解决这个问题吗???

我完全注定了?!?!?!:(

4

1 回答 1

5

@khovanskiiªn - 事情就是这样。尽管您说 EF 的美妙之处,但它并不是为此而设计的。您可以整天对锤子的奇妙之处充满诗意,但如果您的问题需要扳手,它对您无济于事。

有很多解决方案可以满足您的需求,但不要使用 EF 并在 SQL 端执行它,它甚至有一个花哨的名称。它被称为 ETL 或提取/转换/加载,其唯一目的是从一组表中获取数据并将其移动到另一组表中,可能会在两者之间处理数据。

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

事实是,Entity Framework 旨在与单个上下文一起工作,并且它仅跟踪单个上下文中的关系和更改。一旦你将它分开,它就会丢失该信息。

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

帮自己一个忙,看看 SSIS(Sql Server 集成服务)。

于 2012-09-26T18:10:00.110 回答