How to use function in where with ToListAsync()

.net-core async-await c# ef-core-2.1 entity-framework-core

Question

I wrote a where function to check if product have some functionality and find a product with max price.

My simply models look like this:

 public class Product
 {
    public long ProductID { get; set; }
    [MaxLength(150)]
    public string Name { get; set; }

    public List<Functionality> Functionalities { get; set; }
    public List<Price> Prices { get; set; }
 }

 public class Functionality
 {
    public long FunctionalityID { get; set; }
    [MaxLength(150)]
    public string Name { get; set; }

    [Required]
    public long ProductID { get; set; }
    public Product Product { get; set; }
 }

 public class Price
 {
    public long PriceID { get; set; }
    public decimal Value { get; set; }

    [Required]
    public long ProductID { get; set; }
    public Product Product { get; set; }
 }

then my sync function to find correct product look like this:

 public List<Product> GetList(ProductFiltersDto filters)
 {
    return _context.Product
        .Include(x => x.Functionality)
        .Include(x => x.Price)
        .Where(x =>
            CheckCollectionFilter(x.Functionality.Select(f => f.FunctionalityID), filters.Functionalities) &&
            CheckMaximumPrice(x.Prices , filters.MaxPrice)
         )
         .ToList();

 }

below my where function:

private bool CheckCollectionFilter<T>(IEnumerable<T> collection, List<T> filterCollection)
{
    if (filterCollection != null)
    {
        var result = true;
        foreach (var filterValue in filterCollection)
        {
            if (!collection.Contains(filterValue))
            {
                result = false;
                break;
            }
        }

        return result;
     }
     else
     {
         return true;
     }
}

private bool CheckMaximumPrice(List<Price> prices, decimal? avalibleMinPrice)
{
    return avalibleMinPrice.HasValue && prices.Count > 0 ? prices.Min(x => x.Value) <= avalibleMinPrice : true;
}

For above code everything work fine. But when i change ToList() to ToListAsync() i got a error

Expression of type 'System.Collections.Generic.IAsyncEnumerable1[System.Int64]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable1[System.Int64]' of method 'Boolean CheckCollectionFilter[Int64](System.Collections.Generic.IEnumerable1[System.Int64], System.Collections.Generic.List1[System.Int64])' Parameter name: arg0

I try few things to change IEnumerable to IAsyncEnumerable and modify my function to work with asyn version but stil i get error (i dont find a way to change List<long> to IAsyncEnumerable<long> in where clause).

I read that EF Core Async functions have some limitations but maybe someone know is this can be achiev or for now i should leave this and stick with sync solution?

1
1
1/7/2019 8:43:31 PM

Popular Answer

As soon as you move from IQueriable<T> to IEnumerable<T>, EntityFramework will execute the query so far on the database server pulling all that data into memory and will execute the rest of the query in memory.

If you want to keep it running in the database server, you must keep the query an IQueriable<T> and use expression trees instead of executable code.

You will need to come up with something like this:

private Expression<Func<T, bool>> CheckCollectionFilter<T>(IEnumerable<T> filterCollection);

private Expression<Func<T, bool>> CheckMaximumPrice<T>(decimal? avalibleMinPrice);

and change your query to:

_context.Product
    .Include(x => x.Functionality)
    .Include(x => x.Price)
    .Where(CheckCollectionFilter(filters.Functionalities))
    .Where(CheckMaximumPrice(filters.MaxPrice))
3
1/7/2019 10:00:06 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow