I am getting the error asAsync lambda expressions cannot be converted to expression trees
The LINQ query I have is:
public async Task<PaginatedList<BookRequestViewModel>> GetRequestedBookList(int pageNumber, int pageSize)
{
//Getting Error here!!
var results = _dbContext.BookReservations
.Select(async book => new BookRequestViewModel
{
Requester = await _identityService.GetUserEmailAsync(book.RequesterId)
}).PaginatedListAsync(pageNumber, pageSize);
return results;
}
The implementation ofGetUserEmailAsyncis given as:
public interface IIdentityService
{
Task<string> GetUserEmailAsync(string userId);
}
I am trying to convert the result obtained from the LINQ query toPaginatedListAsync, which have the definition as:
public static Task<PaginatedList<TDestination>> PaginatedListAsync<TDestination>(this IQueryable<TDestination> queryable, int pageNumber, int pageSize)
{
return PaginatedList<TDestination>.CreateAsync(queryable, pageNumber, pageSize);
}
The current implementation ofPaginatedList<TDestination>.CreateAsync
public class PaginatedList<T>
{
public List<T> Items { get; }
public int PageIndex { get; }
public int TotalPages { get; }
public int TotalCount { get; }
public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
TotalCount = count;
Items = items;
}
public bool HasPreviousPage => PageIndex > 1;
public bool HasNextPage => PageIndex < TotalPages;
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(items, count, pageIndex, pageSize);
}
}
After finding different resources on the internet I have realized that I have been trying to call the
GetUserEmailAsync unnecessary from the database which is not the correct approach in this situation. I should first fetch the record with the pagination and then GetUserEmailAsync, but I am stuck.
What is the proper way of using the await inside the lambda expressions? How do I approach my LINQ query?
According to your codes,I couldn't reproduce your problems.
As far as I think,you are mixing Expression trees and delegates.
When you pass lambda expression to a method accepting Expression<T>, you create an expression tree from the lambda. Expression trees are just code which describe code, but are not code themselves.
That being said, an expression tree can't be executed because it's converted to executable code. You can compile a expression tree at runtime and then execute it like a delegate.
.NET forums are moving to a new home on Microsoft Q&A, we encourage you to go to Microsoft Q&A for .NET for posting new questions and get involved today.
Thanks for pointing to the solution, but that did not help me to achieve what I want. And still, I couldn't solve the problem. Can you look help me to look into this issue?
I have also changed my code according to the suggestions.
public async Task<PaginatedList<BookRequestViewModel>> GetRequestedBookList(int pageNumber, int pageSize)
{
var bookReservationList = (await _dbContext.BookReservations.Include(x => x.Book).ToListAsync())
.Select(
book => new BookRequestViewModel
{
RequesterId = book.RequesterId,
Author = book.Book.Author
});
var userViewModels = bookReservationList.Select(async y => new BookRequestViewModel
{
Requester = await _identityService.GetUserEmailAsync(y.RequesterId)
});
var vms = await Task.WhenAll(userViewModels);
var result = await vms.AsQueryable().PaginatedListAsync(pageNumber, pageSize);
return result;
}
But got the error as:
InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information
on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
var userViewModels = bookReservationList.Select(async y =>newBookRequestViewModel{Requester= await _identityService.GetUserEmailAsync(y.RequesterId)});var vms = await Task.WhenAll(userViewModels);
the .Select is returning an array of tasks (thus the WhenAll), each of which Is running at the same time. the await in the lambda performs no function as you have no code after the await. as you are using the same dbcontext in each task you get the error.
you appear to think the await would await between tasks.
you could write a .SelectAsync extension that awaited the lambda before looping or use an async line library like reactive.
the simple fix is:
var userViewModels = new List<BookRequestViewModel>();
foreach (var y in bookReservationList)
{
Requester = await _identityService.GetUserEmailAsync(y.RequesterId) });
userViewModels.Add(Requester);
}
Member
5 Points
36 Posts
Async lambda expressions cannot be converted to expression trees
Feb 07, 2021 05:03 PM|aakashbashyal|LINK
I am getting the error as Async lambda expressions cannot be converted to expression trees
The LINQ query I have is:
The implementation of
GetUserEmailAsync
is given as:I am trying to convert the result obtained from the LINQ query to
PaginatedListAsync
, which have the definition as:The current implementation of
PaginatedList<TDestination>.CreateAsync
After finding different resources on the internet I have realized that I have been trying to call the
GetUserEmailAsync
unnecessary from the database which is not the correct approach in this situation. I should first fetch the record with the pagination and then GetUserEmailAsync, but I am stuck.What is the proper way of using the await inside the lambda expressions? How do I approach my LINQ query?
Contributor
3730 Points
1412 Posts
Re: Async lambda expressions cannot be converted to expression trees
Feb 08, 2021 08:00 AM|yij sun|LINK
Hi aakashbashyal,
According to your codes,I couldn't reproduce your problems.
As far as I think,you are mixing Expression trees and delegates.
When you pass lambda expression to a method accepting Expression<T>, you create an expression tree from the lambda. Expression trees are just code which describe code, but are not code themselves.
That being said, an expression tree can't be executed because it's converted to executable code. You can compile a expression tree at runtime and then execute it like a delegate.
More details,you could refer to below article:
https://stackoverflow.com/questions/39518163/using-async-await-inside-select-lambda
Best regards,
Yijing Sun
Member
5 Points
36 Posts
Re: Async lambda expressions cannot be converted to expression trees
Feb 08, 2021 08:05 AM|aakashbashyal|LINK
Hi!
Thanks for pointing to the solution, but that did not help me to achieve what I want. And still, I couldn't solve the problem. Can you look help me to look into this issue?
I have also changed my code according to the suggestions.
But got the error as:
InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
All-Star
58144 Points
15646 Posts
Re: Async lambda expressions cannot be converted to expression trees
Feb 08, 2021 04:31 PM|bruce (sqlwork.com)|LINK
this code:
the .Select is returning an array of tasks (thus the WhenAll), each of which Is running at the same time. the await in the lambda performs no function as you have no code after the await. as you are using the same dbcontext in each task you get the error.
you appear to think the await would await between tasks.
you could write a .SelectAsync extension that awaited the lambda before looping or use an async line library like reactive.
the simple fix is: