LINQ-to-SQL IN / Contains () для Nullable <T> - PullRequest
9 голосов
/ 12 марта 2010

Я хочу сгенерировать этот оператор SQL в LINQ:

select * from Foo where Value in ( 1, 2, 3 )

Сложный бит состоит в том, что Value - это столбец, который допускает нулевые значения.

Эквивалентный код LINQ, по-видимомуbe:

IEnumerable<Foo> foos = MyDataContext.Foos;
IEnumerable<int> values = GetMyValues();
var myFoos = from foo in foos
             where values.Contains(foo.Value)
             select foo;

Это, конечно, не компилируется, поскольку foo.Value является int?, а values имеет тип int.

Я пробовал это:

IEnumerable<Foo> foos = MyDataContext.Foos;
IEnumerable<int> values = GetMyValues();
IEnumerable<int?> nullables = values.Select( value => new Nullable<int>(value));
var myFoos = from foo in foos
             where nullables.Contains(foo.Value)
             select foo;

... и это:

IEnumerable<Foo> foos = MyDataContext.Foos;
IEnumerable<int> values = GetMyValues();
var myFoos = from foo in foos
             where values.Contains(foo.Value.Value)
             select foo;

Обе эти версии дают мне ожидаемые результаты, но они делаютне генерировать SQL, который я хочу.Похоже, что они генерируют результаты полной таблицы, а затем выполняют фильтрацию Contains () в памяти (то есть: в обычном LINQ, без -to-SQL);в журнале DataContext нет предложения IN.

Есть ли способ создать SQL IN для типов Nullable?

NOTE

Как выясняется, проблемаУ меня не было ничего, чтобы сделать Содержит или Nullable, и поэтому формулировка моего вопроса в значительной степени не имеет значения.См. Подробности в ответе Ника Крейвера.

1 Ответ

15 голосов
/ 12 марта 2010

Это должно работать для вашего примера:

IEnumerable<int> values = GetMyValues();
var myFoos = from foo in MyDataContext.Foos;
             where values.Contains(foo.Value.Value)
             select foo;

Преобразование в IEnumerable<T> с начала означает, что выполнение будет выполняться за пределами SQL, вместо этого вызовите IQueryable<Foo> напрямую. Если вы преобразуете в IEnumerable и используете его в запросе, он получает все MyDataContext.Foos, затем использует этот итератор и выполняет остальную часть запроса в C #, а не в SQL.

Если вы хотите работать в SQL, не используйте IEnumerable в любом месте пути. Эффект такой же, как при использовании MyDataContext.Foos.AsEnumerable() в запросе.

...