Связь C # LINQ с сущностями один-ко-многим: проблема с отображением данных последней записи журнала - PullRequest
0 голосов
/ 18 января 2011

У меня есть веб-приложение с двумя таблицами для отслеживания пользовательских ресурсов.Акции должны быть одобрены, и поэтому они проходят серию изменений статуса.Каждое изменение статуса записывается в журнал и ставится метка времени.Текущий статус всегда является последней записью в журнале для этого конкретного ресурса.

Вот сущности (с краткостью):

Shares: ShareID Имя пользователя

ShareLogs: LogIDShareID CreatedDate Status

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

SELECT s.ShareID, s.UserName, sl.Code, sl.CreatedDate
FROM Shares s
INNER JOIN 
(
SELECT s.ShareID, s.Code, s.CreatedDate
    FROM ShareLogs sl
    INNER JOIN (SELECT ShareID, MAX(CreatedDate) logDate FROM ShareLogs GROUP BY ShareID) sl2
        ON sl.ShareID = sl2.ShareID AND sl.CreatedDate = sl2.logDate) psl1
ON s.ShareID = sl1.ShareID
ORDER BY s.ShareID

Я написал один запрос LINQ, который, кажется, работает, но я чувствую, что должен бытьлучше, так как этот запрос выглядит довольно ужасно.

var query = from list in
(from s in context.Shares
join sl in context.ShareLogs on s.ShareID equals sl.ShareID
where sl.CreatedDate == s.ShareLogs.Max(e => e.CreatedDate)
select new
{
 share = s
 status = sl.Code,
 processDate = sl.CreatedDate
}).Where(e => e.status == 2 || e.status == 3)
select list;

Ответы [ 3 ]

0 голосов
/ 19 января 2011
var query = (from s in context.Shares
            let latestOrder = s.ShareLogs                                             
                                         .OrderByDescending(sl => sl.CreatedDate)
                                         .First()
            select new 
            {
                share = s,
                status = latestOrder.Code,
                processDate = latestOrder.CreatedDate
            }).Where(sl => sl.status == 2 || sl.status ==3);

Дайте мне знать, если вы считаете это улучшением.

Редактировать: Я не уверен на 100%, где вам нужен фильтр Где, поэтому я оставил его.Я думаю, что это может быть действительно необходимо в операторе Let.Или мы можем перевести его в синтаксис «Понимание», чтобы он был более последовательным.

0 голосов
/ 19 января 2011

Я предпочитаю синтаксис метода, поэтому вот мой ответ. Обратите внимание, что я также делаю Группу по, но не присоединяюсь.

 context.ShareLogs.GroupBy(log => log.ShareID)
     .Select(g => g.Logs.Single(log => 
         log.CreatedDate == g.Logs.Max(g => g.CreatedDate)))         
     .Select(l => new { Share = l.Share, Status = l.Code, Date = l.CreatedDate });

Вы сможете сгруппировать ShareLogs, чтобы определить правильный объект ShareLog (который содержит код, дату и ShareID), а затем получить общий ресурс, используя свойство навигации log.Share.

Насколько я вижу, объединение не нужно, потому что, как обычно, LINQ скрыло это через свойства навигации.

0 голосов
/ 18 января 2011

Вы можете попробовать выполнить объединение, затем группировать по всем строкам, кроме ShareID, а затем просто получить общий ресурс с наибольшей датой.Например:

var shareList = context.Shares;
var shareLogList = context.ShareLogs;
var join = shareList.Join(shareLogList, o=>o.ShareID, i=>i.ShareID, s=>new{o.ShareID, o.UserName,i.LogID, i.CreatedDate, i.Status});
var query = join.GroupBy(g=>new{g.ShareID,g.UserName}, (key,lines)=>new{key.ShareID, Status = lines.Max(m=>m.CreatedDate).Status});

Это должно сделать это!Вы можете объединить это в одно утверждение, если хотите, я просто разделил их для ясности.

...