Получить максимальную дату из linq с несколькими соединениями и с несколькими полями выбора

#c# #entity-framework #linq #asp.net-core

#c# #entity-framework #linq #asp.net-core

Вопрос:

Я ломал голову над этим и не могу найти решение. У меня есть такой набор данных,

 JobID   DueDate     VisitID
4024082 2020-07-31  5267157
4024082 2020-07-29  5263915
4024082 2020-08-04  5269154
4024082 2020-07-23  5258774
4024082 2020-07-22  5255307
  

Я хочу получить результирующий набор следующим образом,

 JobID   Duedate     VisitID
4024082 2020-08-04  5269154
  

Я пробовал несколько способов, но не могу заставить его работать. мой запрос linq

             var jobs = await (from j in _ctx.Jobs
                              join v in _ctx.Visits on j.JobID equals v.JobID
                              join p in _ctx.Products on j.ProductID equals p.ProductID
                              where j.IsProcessed== true
                              group v by new
                              {
                                  v.JobID,
                                  v.VisitID
                              }
                into g
                              select new
                              {
                                  JobId = g.Key,
                                  DueDate = g.Max(x => x.DueDate),
                                  VisitID = g.Key.VisitID
                              }).ToListAsync();
  

Любая помощь была бы высоко оценена. Спасибо

Комментарии:

1. Я этого не понимаю. Я имею в виду, я вижу только 1 таблицу, но я вижу соединение в вашем SQL-запросе??? значит, больше 1 таблицы?

2. Не включайте DueDate в группу by. Это странно, потому что вы хотите максимальную дату. Я действительно подозреваю, что вы хотите группировать только по идентификатору посещения. JobID Не имеет значения, потому что у вас уже есть where условие для этого идентификатора.

3. @Iria отредактировал и добавил другое объединение. Я не поместил все соединения, чтобы избежать слишком большой путаницы.

4. @Silvermind удалил DueDate. Тем не менее, он возвращает 5 строк для меня вместо 1

5. Я не понимаю эту часть: amp;amp; j.JobID == 4024082 в сочетании с ToListAsync() в конце. Это условие в сочетании с группой выглядит так, как вам нужно FirstOrDefaultAsync() . Возможно, вы добавили это JobID для тестирования, но на самом деле этого нет в запросе, и вы на самом деле ищете максимальное значение duedate и сопутствующий идентификатор посещения для каждого идентификатора задания.

Ответ №1:

Вы не можете использовать Max для получения более одного значения. Здесь вы должны использовать механизм сортировки.

Ниже приведен пример того, как сгруппировать задания по JobID , а затем по каждой самой высокой дате с сопровождением VisitID .

Вот пример. (Я использовал LINQPad для тестирования этого):

 void Main()
{
    var jobs = new[]
    {
        new Job { JobID = 4024082, DueDate = DateTime.ParseExact("2020-07-31", "yyyy-MM-dd", CultureInfo.InvariantCulture), VisitID = 5267157 },
        new Job { JobID = 4024082, DueDate = DateTime.ParseExact("2020-07-29", "yyyy-MM-dd", CultureInfo.InvariantCulture), VisitID = 5263915 },
        new Job { JobID = 4024082, DueDate = DateTime.ParseExact("2020-08-04", "yyyy-MM-dd", CultureInfo.InvariantCulture), VisitID = 5269154 },
        new Job { JobID = 4024082, DueDate = DateTime.ParseExact("2020-07-23", "yyyy-MM-dd", CultureInfo.InvariantCulture), VisitID = 5258774 },
        new Job { JobID = 4024082, DueDate = DateTime.ParseExact("2020-07-22", "yyyy-MM-dd", CultureInfo.InvariantCulture), VisitID = 5255307 },
    };
    
    var query = from job in jobs
                group job by job.JobID into grp
                select grp.OrderByDescending(g => g.DueDate).FirstOrDefault();
    
    query.Dump();
}

public class Job
{
    public int JobID { get; set; }
    public DateTime DueDate { get; set; }
    public int VisitID { get; set; }
}
  

Вывод:

 JobID    DueDate            VisitID
4024082  4-8-2020 00:00:00  5269154 
  

Комментарии:

1. Большое спасибо. Это сработало для меня 🙂 Мне пришлось сначала вставить значения из базы данных в объект класса заданий, а затем запросить объект класса заданий с помощью вашего запроса. Большое спасибо

Ответ №2:

Я думаю, проблема в том, что вы используете VisitId как часть GroupBy . Поскольку все VisitId значения уникальны, вы получите одну запись на группу (и, следовательно, одну группу для каждой записи).

Возможно, вам следует присоединиться только JobId , если вам нужна одна группа из этих образцов записей. Затем, чтобы получить VisitID для строки, в которой была самая последняя DueDate , мы можем упорядочить группу по DueDate (по убыванию) и взять VisitID из First() записи:

 var jobs = await (from j in _ctx.Jobs
                  join v in _ctx.Visits on j.JobID equals v.JobID
                  join p in _ctx.Products on j.ProductID equals p.ProductID
                  where j.IsProcessed== true
                  group v by v.JobID
                  into g
                      select new
                      {
                          JobId = g.Key,
                          DueDate = g.Max(x => x.DueDate),
                          VisitID = g.OrderByDecending(x => x.DueDate).First().VisitID
                      }).ToListAsync();
  

Комментарии:

1. Я получаю эту ошибку, когда использую OrderByDescending для DueDate . Не удалось перевести OrderByDescending(x => x.DueDate)’. Либо перепишите запрос в форме, которая может быть переведена, либо переключитесь на оценку клиента явно, вставив вызов AsEnumerable(), AsAsyncEnumerable(), ToList() или ToListAsync()

2. Можете ли вы попробовать изменить его на VisitID = g.First(x => x.DueDate == g.Max(i => i.DueDate)).VisitID и посмотреть, работает ли это? Извините, я не там, где я могу это проверить в данный момент.

3. Теперь это выдает эту ошибку.Max(i => i.DueDate))’ не удалось перевести. Либо перепишите запрос в форме, которая может быть переведена,