Union (или Concat и т. Д.) С постоянными значениями и проекцией - PullRequest
3 голосов
/ 12 августа 2010

Я обнаружил очень неприятную ошибку с Linq-to-sql, и я не уверен, какое решение лучше.

Если вы берете простое утверждение L2S Union и включаете код L2S вс одной стороны, и константы с другой, то константы не включаются в объединение SQL и проецируются только в вывод после SQL, что приводит к ошибкам SQL относительно количества столбцов, не связанных для объединения.

В качестве примера:

(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo})
.Union(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo})

Это приведет к ошибке "Все запросы, объединенные с использованием оператора UNION, INTERSECT или EXCEPT, должны иметь одинаковое количество выражений в своих целевых списках.

Это особенно коварно (и сводит с ума), потому что в списке, очевидно, одинаковое количество выражений, но когда вы посмотрите на SQL, вы заметите, что он не генерирует столбец для «первого» во второй половине объединения.Это потому, что «Первый» вставляется в проекцию ПОСЛЕ запроса.

Хорошо, простое решение - просто конвертировать each часть в Enumerables или Lists или что-то еще, а затем объединение в памяти, а не в SQL, и это нормально, если вы имеете дело с небольшим количеством данных.Однако, если вы работаете с большим набором данных, которые затем планируете дополнительно отфильтровать (в sql) перед возвратом, это не идеально.

Я думаю, что я ищу способзаставить L2S включить столбец в SQL.Возможно ли это?

ОБНОВЛЕНИЕ:

Хотя это и не точный дубликат, эта ошибка похожа на Этот вопрос и имеет аналогичные решения.Итак, я закрываю, но не удаляю этот вопрос, потому что он может помочь кому-то еще прийти к возможным решениям другим способом.

К сожалению, L2S иногда слишком умён для своего блага.

Ответы [ 2 ]

1 голос
/ 17 ноября 2010

Это ошибка в поставщике Linq2SQL. В LinqPad вы можете ясно увидеть ошибку.

(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo})  
.Union(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo}) 

Будет ли серверная сторона производить что-то вроде этого:

SELECT [t2].[Foo], [t2].[Roo]
FROM (
    SELECT [t0].[Foo], @p0 AS [value]
    FROM [dc].[Mytable] AS [t0]
    UNION ALL
    SELECT [t1].[Foo], [t1].[Roo]
    FROM [dc].[Mytable] AS [t1]
    ) AS [t2]

Это будет проблемой, потому что объединение будет называть второй столбец «value» вместо «Roo», что приведет к сбою внешнего запроса.

Если вы, однако, поменяете порядок двух таблиц

(from e in dc.mytable where foo == "roo" select new {First= "", Second = e.Roo})  
.Union(from d in dc.mytable where foo == "bar" select new {First = d.Foo, Second = d.Roo}) 

Так что постоянное присваивание в сгенерированном T-SQL входит в не первую таблицу, тогда все может работать, поскольку T-SQL игнорирует имена столбцов последующих таблиц.

Примечание. Первая таблица в объединении определяет имя и тип столбца. Так что было бы разумно получить LinqPad в любом случае.

1 голос
/ 29 августа 2010

Я решил, что единственным реальным решением является использование хранимого процесса. Надеюсь, это поможет.

...