LINQ: запрос на самостоятельное соединение, как это сделать? - PullRequest
3 голосов
/ 17 февраля 2011

Может ли кто-нибудь помочь?

У меня есть 1 класс, в основном он содержит членов, и в этом классе есть список.

Члены, которые у меня есть в списке, тоже ... Так что в основномвыглядит так:

У меня есть 2 участника, и у каждого участника есть несколько сессий.

Я хочу вернуть каждого участника только с 1 сессией.

Я сделалLINQ-запрос, но, конечно, он не работает ...

Я думаю, что мне нужно выполнить самостоятельное объединение, есть идеи?

В основном моя ошибка в том, что m не существует в моемподзапрос self join.

var sessions =  
from m in this.members                     
join s in
(
    from se in m.Sessions
    group se by se.Name into g
    select new {Name = g.Key, SessioEndTime = g.Max(a=>a.SessioEndTime)}
)   
on m.Name equals s.Name                    
select new { MemberName = m.Name, SessionTime = s.SessioEndTime}

Буду признателен за любые отзывы.

Заранее спасибо.

РЕДАКТИРОВАТЬ

Хорошо, мне удалось сделать это, как показано ниже, но это лучший способ?

var sessions =  
from m in this.members                     
let sn = m.Sessions.OrderByDescending(a => a.SessionEndTime).FirstOrDefault()                
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime}

Таким образом, sn содержит 1 запись, но у меня есть доступ ко всем свойствам ...

Но разве это лучший способ использовать LET?

Спасибо.

1 Ответ

5 голосов
/ 17 февраля 2011

Если я не пропустил что-то, что вам нужно, нет?

var sessions = 
   from m in members
   select new { 
      MemberName = m.Name, 
      SessionTime = m.Sessions.Max(s => s.SessioEndTime)
   };

Вы должны изменить свой подход к LINQ-запросам, больше думать с точки зрения объекта, а не с точки зрения реализации SQL. Что мне нужно? Мне нужно, чтобы все участники, каждый со своим последним временем окончания сеанса, затем приступили к этому.

EDIT: С опцией let, которую вы использовали, все в порядке, просто имейте в виду, что FirstOrDefault вернет ноль, если у члена пустой список сессий, а затем sn.SessionEndTime попадет на нулевую ссылку. Если, с другой стороны, вы уверены, что у каждого участника есть хотя бы один сеанс, используйте First вместо или агрегируйте. Также не используйте FirstOrDefault() в let, это как-то портит LINQ и не позволяет ему привязать его к мастеру (вызывая отдельный SQL-запрос для каждого мастера, чтобы обнаружить недостающие подмножества), поэтому используемые запросы с let:

from m in Members                     
let sn = m.Sessions.Max(s => s.SessioEndTime)                
select new { MemberName = m.Name, SessionTime = sn};

from m in Members                     
let sn = m.Sessions.OrderByDescending(a => a.SessioEndTime).First()              
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime};

Что касается упорядочения в сравнении с агрегацией Max, оба запроса будут генерировать подзапрос:

-- MAX    
SELECT [t0].[Name] AS [MemberName], (
    SELECT MAX([t1].[SessioEndTime])
    FROM [Session] AS [t1]
    WHERE [t1].[memberId] = [t0].[id]
    ) AS [SessionTime]
FROM [Member] AS [t0]
GO

-- ordering
SELECT [t0].[Name] AS [MemberName], (
    SELECT [t2].[SessioEndTime]
    FROM (
        SELECT TOP (1) [t1].[SessioEndTime]
        FROM [Session] AS [t1]
        WHERE [t1].[memberId] = [t0].[id]
        ORDER BY [t1].[SessioEndTime] DESC
        ) AS [t2]
    ) AS [SessionTime]
FROM [Member] AS [t0]

При нисходящем индексе в SessioEndTime скрипт упорядочения примерно в два раза медленнее (вы можете получить планы выполнения, чтобы проверить их самостоятельно), без индекса он примерно в 5 раз медленнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...