3

序文

これはおそらくすでにクレイジーな質問と見なされていることを知っていますが、すべてのデータ (つまり、すべてのエンティティと関係) を から別のストアにバックアップされた新しく作成された にコピーする方法について、最も教育を受けたアドバイスと実証済みの推奨事項を探しています。 . Entity Framework での EntityConnections と ObjectContexts の「複製」を参照して、これをどのように設定しているかを確認してください。ObjectContextObjectContext


はじめに

Cloning data on Entity Frameworkを見てきましたが、

  1. enchilada 全体、つまりオブジェクト グラフ全体 (すべてのエンティティと関係)を探しています。後で、オブジェクト グラフのどの部分をより細かく選択するかについて説明します)

  2. 以下の私の更新によると、私はシリアル化を機能させていませんが、特別な場合にのみ使用しています。それほど複雑な作業ではないように感じますが、驚くほどやりがいがあります。それを機能させる方法についての洞察が絶対に必要です。


ステップ1

OK、これは私がこれまでに試したことです。

Detach/パワー デュオを使用するとAttach、リレーションシップが無効になることは承知しています。<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場合にのみ呼び出すことができます。」EntityCollectionEntityReference

(シリアライザーはおそらく関連するエンティティを遅延ロードしようとしているため、これは理にかなっています。)

を使用しない場合はNoTracking、エンティティをデタッチする必要がありますが、関係が失われることを覚えておいてください...


ステップ2

もちろんsourceContext.ContextOptions.LazyLoadingEnabled = false、シリアル化ループを実行する直前に設定を試みましたが、上記のエラーは修正されましたが、悪名高い結果になります:

「このオブジェクトの と一致しないプロパティ値EntityReferenceがあるため、オブジェクトを追加または添付できませんでした。」EntityKeyEntityKey

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 はこれを行うようには設計されていません。ハンマーの素晴らしさについて一日中詩的に語ることはできますが、問題がレンチを必要とする場合は役に立ちません。

あなたが望むことをするソリューションはたくさんありますが、EFを使用せずにSQL側で実行してください。派手な名前さえあります。これは ETL または Extract/Transform/Load と呼ばれます。唯一の目的は、1 つのテーブル セットからデータを取得して別のテーブル セットに移動し、その間にデータを処理することです。

実際、これらのツールをクライアント コードとシームレスに統合できます。たとえば、SSIS パッケージをクライアント コードから実行し、パラメーターを渡して、どのデータを処理するかを制御できます。

実際のところ、Entity Framework は単一のコンテキストで動作するように設計されており、単一のコンテキストでの関係と変更のみを追跡します。分離するとすぐに、その情報が失われます。

さらに、EF は一括操作やバッチ操作ではなく、単一のエンティティで動作するため、エンティティ フレームワークはこの種のことに対して非常に非効率的です。100 万件のレコードがある場合、1 回の操作を実行するのに 1 日かかることがありますが、SQL 側のバッチ操作には数分かかることがあります。

SSIS(Sql Server Integration Services)を調べてください。

于 2012-09-26T18:10:00.110 に答える