2010-03-11 5 views
4

Мне кажется, что важно, используете ли вы переменную для временного хранения IQueryable или нет. Смотрите упрощенный пример ниже:Linq to SQL дает NotSupportedException при использовании локальных переменных

Это работает:

List<string> jobNames = new List<string> { "ICT" }; 
var ictPeops = from p in dataContext.Persons 
       where ( from j in dataContext.Jobs 
         where jobNames.Contains(j.Name) 
         select j.ID).Contains(p.JobID) 
       select p; 

Но когда я использую переменную для временного хранения подзапрос я получаю исключение:

List<string> jobNames = new List<string> { "ICT" }; 
var jobs = from j in dataContext.Jobs 
      where jobNames.Contains(j.Name) 
      select j.ID; 
var ictPeops = from p in dataContext.Persons 
       where jobs.Contains(p.JobID) 
       select p; 

«System.NotSupportedException: Запросы с местными коллекциями не являются "

Я не понимаю, в чем проблема. Разве не эта логика должна работать в LINQ?

UPDATE: Вчера я нашел обходной путь, чтобы получить 1 запрос с использованием нескольких переменных:

var jobs = from j in dataContext.Jobs 
      where jobNames.Contains(j.Name) 
      select j.ID; 
    var ictPeops = from p in dataContext.Persons 
       join j in jobs on p.JobID equals j 
       select p; 

Но все-таки я запутался. Может ли кто-нибудь пролить свет на то, почему первый запрос не работал при использовании переменной?

+0

Я не смог воспроизвести это. пожалуйста, загрузите yout Linq в схему SQL и отправьте нам ссылку – Andrey

ответ

3

LINQ-2-SQL переводит ваш код в T-SQL. Он может легко передавать список имен заданий в качестве параметра. Но в вашем неудачном запросе вы пытаетесь присоединиться к таблице SQL (Person) к объекту C# (задания); это сложный тип C#, который нельзя преобразовать в SQL. Вероятно, вам нужно преобразовать задания в простой массив int, прежде чем использовать его во втором запросе. LINQ-2-SQL может справиться с этим.

+0

Я не думаю, что вы понимаете проблему. «Сложный» тип C#, на который вы ссылаетесь, является IQueryable , источником которого является тот же файл данных. Когда я конвертирую его в IEnumerable (например, массив), он работает, но linq2sql будет выполнять 2 запроса. Это не вариант. – nicojs

+0

Я думаю, что созданное исключение описало проблему довольно кратко: «Запросы с локальными коллекциями не поддерживаются». Это ограничение LINQ-2-SQL. –

+0

Если jobNames - это простая структура данных (то есть List, Array), тогда код «where jobNames.Contains (j.Name)» приводит к SQL, который выглядит так: «WHERE Name IN (@ p0, @ p1, ...)» , Но так как jobNames является IQueryable, L2S не может перевести это. Ваш третий пример работает, потому что синтаксис отличается: «join j в заданиях на p.JobID равно j». На данный момент L2S знает, что «j» ссылается на таблицу Jobs, поэтому полученный SQL выглядит примерно так: «FROM [Персоны] AS [t0] INNER JOIN [Имена] AS [t1] ON [t0]. [JobID] = [t1]. [ID] " –

-1

Позвольте мне объяснить, как работает Linq to SQL. Когда вы пишете запрос в коде, этот код не выполняется как другой .net-код и Linq для объектов. Затем этот код разбивается на дерево выражений и компилируется в SQL. Если вы пишете все как одно выражение, оно полностью преобразуется в SQL. Когда вы переходите на два запроса, он разбивается на два отдельных запроса. И Linq To SQL не может их собрать.

+0

Это неверно. Поскольку два запроса являются двумя деревьями выражений, LINQ to SQL будет производить один оператор SQL. Это не проблема. – Steven

+0

«LINQ to SQL будет производить один оператор SQL» - можете ли вы это доказать? – Andrey

+0

См. Мое обновление, если запрос linq генерирует следующий запрос: SELECT [t0]. [ID], [t0]. [Name], [t0]. [JobID] FROM [dbo]. [Person] AS [t0] INNER JOIN [dbo]. [Job] AS [t1] ON [t0]. [JobID] = [t1]. [ID] WHERE [t1]. [Name] IN (@ p0) - @ p0: Входной файл NVarChar (размер = 3; Prec = 0; Scale = 0) [ICT] - Контекст: SqlProvider (Sql2008) Модель: AttributedMetaModel Build: 3.5.30729.1 – nicojs

0

попытка преобразования вар jobs типу IList

var jobs = (from j in dataContext.Jobs 
      where jobNames.Contains(j.Name) 
      select j.ID).ToList(); 
+0

Нет, это не то, что я ищу.Конечно, ToList будет работать, но генерируется 2 запроса. В моем бизнесе это означало бы, что второй запрос выбора будет иметь около 30000 параметров ввода, и это не должно быть решением. – nicojs

0

Из любопытства, делает эту работу? (Я не большой чувак LINQ к SQL)

var jobNames = from s in new string[] { "ICT" } 
     select s; 
var jobs = from j in dataContext.Jobs 
     where jobNames.Contains(j.Name) 
     select j.ID; 
var ictPeops = from p in dataContext.Persons 
      where jobs.Contains(p.JobID) 
      select p; 

EDIT: Хорошо, как насчет один большой запрос? :)

var ictPeops = 
    from p in dataContext.Persons 
     let jobs = 
      from j in dataContext.Jobs 
      let jobNames = from s in new string[]{"ICT"} select s 
      where jobNames.Contains(j.Name) 
      select j.ID 
    where jobs.Contains(p.JobID) 
    select p; 
+0

Нет, та же проблема. Первая часть будет работать, потому что jobNames имеет тип IEnumerable и обрабатывается так же, как и список строк, которые я использовал. Такая же проблема с выбором, если ictPeops, хотя .... – nicojs

+0

Хм ... хорошо, еще одна идея - проверить правку. – JerKimball

+0

Нет, со вторым запросом я получаю то же известное System.NotSupportedException. Обратите внимание, что мой самый первый запрос действительно работает. – nicojs

Смежные вопросы