Linq-to-Sql: как указать условие, которое проверяет значение, содержащееся в некотором пуле, но имеет дополнительное значение, которое необходимо проверить - PullRequest
0 голосов
/ 28 октября 2011

Хорошо, это трудно объяснить в названии выше. Так что здесь, надеюсь, понятнее:

Допустим, у меня есть пул номеров документов и связанных с ними областей (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, Площадь] .key' не поддерживает перевод на SQL.

Может кто-нибудь помочь, пожалуйста?

Ответы [ 2 ]

1 голос
/ 28 октября 2011

LINQ to SQL не имеет способа представления поиска в памяти Dictionary как SQL.Один из способов - использовать 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 на стороне сервера.стол (который вы можете присоединить с помощью documents), возможно, даже временный стол (в зависимости от ваших потребностей).

--- EDIT ---

Если , то Dictionary мала, а таблица большая, но хорошо проиндексирована, возможно, стоит выполнить отдельный запрос для каждого искомого значения.Например:

class Program {

    static void Main(string[] args) {

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

        using (var ctx = new DataClasses1DataContext()) {

            ctx.Log = Console.Out;

            var rows = new List<Document>();
            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) и работает очень плохо, если в словаре много элементов.

0 голосов
/ 28 октября 2011

Содержит может использовать простой массив отдельных значений и преобразовать его в предложение Where x In {a,b,c} в SQL. Я не думаю, где ... В может поддерживать несколько столбцов в 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...