Не удалось отформатировать узел «Значение» для выполнения как SQL

Я наткнулся на очень странное поведение / ошибку LINQ to SQL, которую просто не могу понять.

Давайте возьмем следующие таблицы в качестве примера: Клиенты -> Заказы -> Детали.
Каждая таблица является подтаблицей предыдущей таблицы с обычным отношением первичного и внешнего ключей (от 1 ко многим).

Если я выполню следующий запрос:

var q = from c in context.Customers
        select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();

Тогда я получу исключение: Не удалось отформатировать узел «Значение» для выполнения как SQL .

Но следующие запросы не вызывают исключения:

var q = from c in context.Customers
        select (c.Orders.FirstOrDefault() ?? new Order()).OrderDateTime;
var q = from c in context.Customers
        select (new Order()).Details.Count();

Если я изменю свой основной запрос следующим образом, я не получу исключения:

var q = from r in context.Customers.ToList()
        select (c.Orders.FirstOrDefault() ?? new Order()).Details.Count();

Теперь я могу поймите, что последний запрос работает по следующей логике:
Поскольку нет сопоставления "new Order ()" с SQL (я предполагаю здесь), мне нужно вместо этого работать с локальным списком.

Но я не могу понять, почему работают два других запроса ?!?

Я потенциально мог бы согласиться работать с "локальной" версией context.Customers.ToList () , но как ускорить запрос?
Например, в В последнем примере запроса я почти уверен, что каждый выбор вызовет выполнение нового SQL-запроса для получения заказов. Теперь я мог бы избежать отложенной загрузки, используя DataLoadOptions , но тогда я бы извлекал тысячи строк Order без всякой причины (мне нужна только первая строка) ...
Если бы я мог выполнить весь запрос в одном операторе SQL, как я хотел бы (мой первый пример запроса), тогда сам механизм SQL был бы достаточно умен, чтобы получать только одну строку заказа для каждого клиента ...

Возможно, существует способ переписать мой исходный запрос таким образом, чтобы он работал по назначению и выполнялся одним махом сервером SQL?

РЕДАКТИРОВАТЬ:
(более длинный ответ для Артуро)
Запросы, которые я предоставил, предназначены исключительно для примера. Я знаю, что они бессмысленны сами по себе, я просто хотел показать упрощенный пример.

Причина, по которой ваш пример работает, заключается в том, что вы полностью избегали использования «new Order ()». Если я немного изменю ваш запрос, чтобы по-прежнему его использовать, то все равно получу исключение:

var results = from e in (from c in db.Customers
                         select new { c.CustomerID, FirstOrder = c.Orders.FirstOrDefault() })
              select new { e.CustomerID, Count = (e.FirstOrder != null ? e.FirstOrder : new Order()).Details().Count() }

Хотя на этот раз исключение немного другое - не удалось отформатировать узел «ClientQuery» для выполнения как SQL.
Если я использую синтаксис ?? вместо (x? Y: z) в этом запросе, я получаю то же исключение, которое было у меня изначально.

В моей реальной жизни запрос Мне не нужен Count () , мне нужно выбрать пару свойств из последней таблицы (которые в моих предыдущих примерах были бы Details). По сути, мне нужно объединить значения всех строк в каждой таблице. Чтобы привести более объемный пример, мне сначала придется переформулировать свои таблицы:

Модели -> Варианты категорий моделей <- Варианты категорий -> Элементы Вариации категории -> МоделиМодульКатегорииВариацияЭлементыМодели -> ModelModuleCategoryVariationItemAmountValueChanges] [11102] представляет [11102] отношение 1 -> многие . Обратите внимание, что есть один знак, который говорит об обратном ... Если я правильно помню, при использовании let mmcvia = new ModelModuleCategoryVariationItemAmount () запрос взорвался бы при следующем операнде ?? , который находится на Amount = .
Если я начну запрос с из m в context.Models.ToList () , тогда все будет работать ...

9
задан Marko 5 May 2011 в 08:12
поделиться