'LINQ Expression GroupBy Select First

I've got a question on LINQ Expression. I need to replicate the following lambda:

var result = processRevisions
   OrderByDescending(pr => pr.CreatedAt)
   GroupBy(pr => pr.IdProcess)
   Select(pr => pr.First());

which result is the latest revision created for every process, in LINQ expression.

I start with this code:

Expression<Func<ProcessRevision, DateTime>> orderProcessRevision = f => f.CreatedAt;
Expression<Func<ProcessRevision, long>> groupProcessRevision = f => f.IdProcess;
Expression<Func<ProcessRevision, ProcessRevision>> selectProcessRevision = f => f;

processRevisions = await processRevisionRepository.GetDatasByLastRevisionAsync(orderProcessRevision, groupProcessRevision, selectProcessRevision);

The repository is as follows:

public async Task<IEnumerable<T>> GetDatasByLastRevisionAsync(
   Expression<Func<T, DateTime>> order,
   Expression<Func<T, long>> group,
   Expression<Func<T, T>> select)
{
   IQueryable<T> query = dbContext.Set<T>();

   query = query.OrderByDescending(order);
   query = query.GroupBy(group);
   query = query.Select(select);

   return await query.ToListAsync();
}

The only part of the query which works is the orderbydescending. Then, the groupby yields an error (implicit convert IGrouping to IQueryable) and also the select first item of each group goes in error.

How to apply the groupby (igrouping) to IQueryable and for every group take the first object?

Thanks for help.



Solution 1:[1]

I think the issue is that GroupBy doesn't return an IQueryable<T> but an IEnumerable<TResult> where TResult is of type IGrouping<TKey, TElement>.

Expression<Func<ProcessRevision, DateTime>> orderProcessRevision = f => f.CreatedAt;
Expression<Func<ProcessRevision, long>> groupProcessRevision = f => f.IdProcess;
// Fix the type and update the lambda to select the first item in the group
Expression<Func<IGrouping<long, ProcessRevision>, ProcessRevision>> selectProcessRevision = f => f.First();

processRevisions = await processRevisionRepository.GetDatasByLastRevisionAsync(orderProcessRevision, groupProcessRevision, selectProcessRevision);

public async Task<IEnumerable<T>> GetDatasByLastRevisionAsync(
   Expression<Func<T, DateTime>> order,
   Expression<Func<T, long>> group,
   Expression<Func<IGrouping<long, T>, T>> select)
{
   IQueryable<T> query = dbContext.Set<T>();

   query = query.OrderByDescending(order);
   // Don't reassign, create a new var
   var grouped = query.GroupBy(group);
   var selected = grouped.Select(select);

   return await selected.ToListAsync();
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Emaro