積極的な読み込みデータマッパーのフェッチ深度を制御するにはどうすればよいですか?
-
05-07-2019 - |
質問
Lazy属性がアタッチされていないプロパティを積極的に読み込むデータマッパークラスがあります。州と国の2つのエンティティがあります。国はその国のすべての州のリストを含むという点で州と逆の関係を持ち、州は国との順方向の関係を持ちます。に割り当てられます。ただし、これらのオブジェクトのいずれかを取得しようとすると、状態が次のようになります。
- 状態はマッパーによってロードされます
- マッパーが熱心な国に到達
- マッパーはその州の国を取得します
- マッパーが国を読み込みます
- マッパーは州の熱心なコレクションプロパティに到達しました
- マッパーは状態のリストをロードし、可能な場合はキャッシュを使用して個々の状態のマッピングを開始します。
- 国に積まれた各州のGOTO 1
このループを回避する方法について私は途方に暮れています。だから、主にアイデアを探しています。誰もが尋ねるコードを投稿しますが、このプロセスには大量のコード行が含まれるため、質問をコードであふれさせたくありませんでした。
事前に感謝します!
編集:
Matt Howellsのアドバイスに従い、データマッパーパターンの詳細を調査した後、Martin Fowlerは確かに169および170ページの循環参照について語っています。再帰的な読み込みを停止します。私はこの段落を約1000回読んでいますが、これがロードを停止する方法と、それを超えてこの空のオブジェクトをアイデンティティマップにロードするタイミングまたは方法を知る方法が失われていることをまだ理解していません。ここで密度が高くなっていることをおaびしますが、これはちょうど私の頭上を飛んでいるようです。
ありがとうございます。
解決
どのオブジェクトがロードされたかを追跡するリポジトリを介してオブジェクトをロードすることを検討してください。
編集:自分でORMを実行している場合(およびそうでない場合でも)、Martin Fowlerの著書 『Patterns of Enterprise Application Architecture』を強くお勧めします。私は彼が本の中でこのループ状況について話しているのを漠然と覚えているので、あなたを助けるかもしれません。
編集2: ループのステップ4および5で、すでに国をロードしている場合は、国をロードする必要があるため、国を積極的にロードする必要はありません。これにより、無限ループが解除されます。
他のヒント
データマッパーは循環参照をキャッチする必要があります。自家製のデータマッパーですか?
思いついた解決策を投稿したかっただけですが、この猫の皮を剥ぐ方法はたくさんあると思います。
作成したFetchDepthCounterClassは次のとおりです。
public static class FetchDepthCounter
{
private static Dictionary<Type, int> _DepthCounter;
private static int _MaxDepth = 3;
static FetchDepthCounter()
{
_DepthCounter = new Dictionary<Type, int>();
}
public static void SetDepth(int depth)
{
_MaxDepth = depth;
}
public static void ResetCounter()
{
_DepthCounter.Clear();
}
public static bool IncrementCounter(Type entityType)
{
if(!_DepthCounter.ContainsKey(entityType))
{
_DepthCounter.Add(entityType, 0);
return true;
}
if(_DepthCounter[entityType] < _MaxDepth)
{
++_DepthCounter[entityType];
return true;
}
return false;
}
}
IncrementCounterは、最大フェッチ深度に到達したかどうかを示すブール値を返します。プロパティの値を設定する直前に、マッピングプロセスの一部としてインクリメントカウンターを呼び出します。最初に、ロードする必要があるのは別のDTOオブジェクトまたはDTOのコレクションであると判断し、 parent タイプを渡し、そのタイプで増分します。したがって、これはデータマッパーのSetValueメソッド内の小さなコードです:
if(isDto)
{
if (!FetchDepthCounter.IncrementCounter(property.ComponentType))
return;
}
それはそうです、それはそれをするようです。私の単体テストはすべて合格しています。みんなの助けてくれてありがとう。これが後で誰かを助けることを願っています。繰り返しになりますが、これはおそらく作業単位パターンでラップする方がはるかに簡単だったでしょうし、最終的にはそれを行うかもしれませんが、これで今のところ仕事は完了です。