3

サードパーティが提供するデータベースに対して Linq2SQL クエリを実行しています。クエリの主要部分は次のようになります。

         var valuationQuery =
            from v in context.Valuations
            where v.ModelId == QualifiedModelId.ModelId
                && v.QualifyModelId == QualifiedModelId.Qualifier
                && v.LanguageCode == QualifiedModelId.LanguageCode
                && v.Edition == Data.Meta.Edition.CurrentEdition.Date
                && v.RegDate == yearReg.RegistrationDate
                && v.ValTypeDescription == "Normal"
                && v.MileageBandID == MileageBand

foreachループでループすると、最後の選択に応じて機能するか失敗します。選択がこのようなすべてのフィールドを指定すると...

            select new
            {
                v.Value1,
                v.Value2,
                v.Value3,
                ... snip ...
                v.Value14,
                v.Value15,
                v.ValueTypeID
            };

...正常に動作します。以下を実行すると、ループは正しい回数反復しますが、毎回最初のレコードを返します。

            select v;

ベンダーがさらにフィールドを追加した場合に備えて、名前を指定せずにすべてのフィールドを選択できるようにしたいと考えています (実際には「Value1」から「Value15」までと呼ばれます)。つまり、コード内の 1 つの定数を変更して DBML を更新し、関連するすべてのコードは、正しい数のフィールドから検索されます。このクエリ (および同様のクエリ) はさまざまな場所で使用されているため、将来的には最小限の労力で済むものを探しています!

実行中のクエリが正しい結果を返すことを確認するために SQL プロファイラーを実行しました。

foreach ループは次のとおりです (Convert は、非常に一貫性のないデータ型を持つ非常に設計の悪いデータベースが原因です)。

  foreach (var record in valuationQuery)
      {
            int CurrentValType = Convert.ToInt32(record.ValueTypeID);
            string FieldName = "Value";

            if (MPLower.MileagePointID >= 1 && MPLower.MileagePointID <= MaxMileagePoints)
            {
                FieldName = "Value" + MPLower.MileagePointID.ToString().Trim();
                MPLower.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
            }

            if (MPHigher.MileagePointID >= 1 && MPHigher.MileagePointID <= MaxMileagePoints)
            {
                FieldName = "Value" + MPHigher.MileagePointID.ToString().Trim();
                MPHigher.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
            }
        }

私は C# を初めて使用するので (いくつかのコードを継承しています)、おそらくそれは私が行った、または行っていない愚かなことだと思います!! 誰でも助けてください。

4

1 に答える 1

3

アイデンティティ マップ

ORM を使用する際の一般的な問題 (まったく一般的ではないかもしれませんが、発生する可能性があります) は、異なるレコードを返すことを期待しているクエリが、同じレコードの複数のコピーを返すことです。これは、ORM の ID マップが原因であることがよくあります。ここでは、通常の動作の概要を簡単に説明します。

ID マップは、基本的に、各オブジェクトの主キーに基づくオブジェクト キャッシュです。

ORM に特定の主キーを持つレコードを要求すると、ID マップにそのレコードが既に存在するかどうかがチェックされます。既に存在する場合は、既存のレコードを返します。

これは通常は非常に便利ですが、時々うまくいかないことがあります。2 つのオブジェクトが同じ主キーを持っている場合、または主キーが何であるかを指定していない (ORM に強制的に推測させる) 場合、ID マップはそれらを区別できず、常に最初のものが返されます。

この話の教訓は、あるべきではない場所に同じレコードの複数のコピーが表示されている場合は、主キーを常に再確認することです。


この質問では、コード

    select new
    {
        v.Value1,
        v.Value2,
        v.Value3,
        ... snip ...
        v.Value14,
        v.Value15,
        v.ValueTypeID
    };

select new{} プロジェクションを使用して匿名型を返し、アイデンティティ マップをバイパスしているため、機能します。

    select v

オブジェクトを直接選択します。これはアイデンティティ マップを使用するため、問題が発生します。

于 2013-05-03T15:52:44.600 に答える