Как я могу заставить это SelectMany использовать Join? - PullRequest
5 голосов
/ 07 июля 2011

Учитывая, что у меня есть три таблицы (Customer, Orders и OrderLines) в модели Linq To Sql, где

Клиент - Один ко многим -> Заказы - Один ко многим -> Строки заказа

Когда я использую

var customer = Customers.First();
var manyWay = from o in customer.CustomerOrders
              from l in o.OrderLines
              select l;

Я вижу, что один запрос получает клиента, это имеет смысл. Затем я вижу запрос для заказов клиента, а затем один запрос для каждого заказа, получающий строки заказа, а не объединяющий их. Всего n + 1 запросов (не считая получения клиента)

Но если я использую

var tableWay = from o in Orders
               from l in OrderLines
               where o.Customer == customer
               && l.Order == o
               select l;

Тогда вместо того, чтобы видеть один запрос для каждого заказа, получающего строки заказа, я вижу один запрос, соединяющий две таблицы. Всего 1 запрос (не считая получения клиента)

Я бы предпочел использовать первый запрос Linq, так как он кажется мне более читабельным, но почему L2S не присоединяется к таблицам, как я ожидал в первом запросе? Используя LINQPad, я вижу, что второй запрос компилируется в SelectMany, хотя я не вижу изменений в первом запросе, не уверен, является ли это индикатором какой-либо проблемы в моем запросе.

Ответы [ 5 ]

2 голосов
/ 07 июля 2011

Я думаю, что ключ здесь

customer.CustomerOrders

То есть EntitySet, а не IQueryable, поэтому ваш первый запрос не переводится напрямую в SQL-запрос.Вместо этого он интерпретируется как множество запросов, по одному на каждый Орден.

В любом случае, это мое предположение.

1 голос
/ 07 июля 2011

Итак, после ответа Франциско и экспериментов с LINQPad я нашел достойное решение.

var lines = from c in Customers
            where c == customer
            from o in c.CustomerOrders
            from l in o.OrderLines
            select l;

Это вынуждает EntitySet в выражение, которое провайдер затем превращает в соответствующий запрос. Первые две строки являются ключом, запрашивая IQueryable и , затем , помещая EntitySet в SelectMany, он становится выражением. Это работает и для других операторов: Где, Выбрать и т. Д.

1 голос
/ 07 июля 2011

Попробуйте этот запрос:

IQueryable<OrderLine> query =
  from c in myDataContext.customers.Take(1)
  from o in c.CustomerOrders
  from l in o.OrderLines
  select l;

Вы можете перейти к определению свойства CustomerOrders и посмотреть, как действует свойство, когда оно используется с фактическим экземпляром. Когда свойство используется в выражении запроса, поведение зависит от поставщика запроса - в этом случае код свойства обычно не запускается.

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

1 голос
/ 07 июля 2011

Я не уверен на 100%. Но я предполагаю, что вы пересекаете взаимосвязь, в соответствии с которой создается запрос, по сравнению со вторым решением, где вы фактически объединяете два набора по значению.

1 голос
/ 07 июля 2011

Как насчет этого:

Customers.First().CustomerOrders.SelectMany(item => item.OrderLines)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...