Linq-to-Sql:いくつかのプールに含まれている値をチェックする条件を指定する方法ですが、チェックする必要がある追加の値が関連付けられています

さて、上記のタイトルで説明するのは難しいです。だから、ここでそれはうまくいっています。

ドキュメント番号と関連する領域(DocNum、Area)のプールがあるとします。 (AB、1)、(GH、2)、(UI、3)

今私は、データベースからの値の組み合わせを持つすべてのドキュメントの情報を取得するLinq-to-Sqlクエリを書いて、どのようにそれを行う必要がありますか?私はそれが辞書を使って行うことができると思ったので:

var data = from document in context.documents
           where dictionary.Contains(new KeyValuePair(document.DocNum, document.Area))
           select new
           {
               ...whatever
           }

このようにしようとすると、次のエラーが表示されます。

System.NotSupportedException:メンバー   'System.Collections.Generic.KeyValuePair`2 [System.String、Area] .Key'   SQLへの変換はサポートされていません。

誰でも助けてくれますか?

0

2 答え

LINQ to SQLには、メモリ内の Dictionary 検索をSQLとして表す方法がありません。これを回避する方法の1つは、 AsEnumerable を使用してLINQ to Objectsを使用することです。

var data = from document in context.documents.AsEnumerable()
       where dictionary.Contains(new KeyValuePair(document.DocNum, document.Area))
       select new
       {
           ...whatever
       }

これは、 context.documents からすべての行を取得していることを意味します。小さなテーブルの場合、これは問題ではありませんが、大きなテーブルの場合は、このようなフィルタリングをSQLで直接実行することを検討する必要があります。 Dictionary を( document で)JOINできるサーバー側のテーブルに置き換えたり、一時テーブル(必要に応じて)を使用することもできます。

---編集---

If the Dictionary is small and the table is large but well indexed, it might be worth executing a separate query for each value being searched. For example:

class Program {

    static void Main(string[] args) {

        var criteria = new Dictionary, object> {
            { new KeyValuePair("n1", "a1"), null },
            { new KeyValuePair("n2", "a2"), null },
            { new KeyValuePair("n3", "a3"), null },
        };

        using (var ctx = new DataClasses1DataContext()) {

            ctx.Log = Console.Out;

            var rows = new List();
            foreach (var criterion in criteria.Keys) {

                var q = from document in ctx.Documents
                    where document.DocNum == criterion.Key && document.Area == criterion.Value
                    select document;

                rows.AddRange(q);

            }

            foreach (var row in rows)
                Console.WriteLine("{0}, {1}", row.DocNum, row.Area);

        }

    }

}

これにより、次の出力が表示されます。

SELECT [t0].[DocNum], [t0].[Area]
FROM [dbo].[Document] AS [t0]
WHERE ([t0].[DocNum] = @p0) AND ([t0].[Area] = @p1)
-- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [n1]
-- @p1: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [a1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

SELECT [t0].[DocNum], [t0].[Area]
FROM [dbo].[Document] AS [t0]
WHERE ([t0].[DocNum] = @p0) AND ([t0].[Area] = @p1)
-- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [n2]
-- @p1: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [a2]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

SELECT [t0].[DocNum], [t0].[Area]
FROM [dbo].[Document] AS [t0]
WHERE ([t0].[DocNum] = @p0) AND ([t0].[Area] = @p1)
-- @p0: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [n3]
-- @p1: Input NVarChar (Size = 4000; Prec = 0; Scale = 0) [a3]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

n1, a1
n2, a2
n3, a3

ただし、これは Dictionary の本来の検索機能を浪費します(これは他の IEnumerable でも可能です)。

1
追加された

Containsは単一の値の単純な配列を使用し、それをSQLの Where x In {a、b、c} 節に変換できます。私はWhere ... InがSQLの複数の列をサポートできるとは思わない。その結果、実際には(SQL - 82スタイルの)結合または複合が必要になります。次のように、オブジェクトコレクションをテーブルに結合できます(オブジェクトコレクションへのテーブルではありません)。

var data = from dict in dictionary.Values
           join document in context.documents 
           on new {dict.DocNum, dict.Area} equals new {document.DocNum, document.Area}
           select new {};

ただし、これにより、ドキュメントテーブル全体がメモリに格納され、LINQ to Objectsを介して結合が行われる必要があります。

0
追加された
参考までに、OracleではINの複数の列をサポートしていますが、他のほとんどのデータベースではそうではありません。いずれの場合でも、ほとんどのデータベースはSQL文のサイズと IN(...)リスト自体のサイズに制限があります(たとえば、このリストには10​​00個以下の項目が許可されています)。
追加された 著者 Branko Dimitrijevic,
SQL Serverには、inパラメータの数に同様の制限があります。 OPはLINQ to SQLを使用しているので、この場合はOracle以外のSQL Serverを使用していると想定しますが、その違いについて知っておくとよいでしょう。
追加された 著者 Jim Wooley,