简体   繁体   中英

How to use function in where with ToListAsync()

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.IAsyncEnumerable 1[System.Int64]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable 1[System.Int64]' of method 'Boolean CheckCollectionFilter[Int64](System.Collections.Generic.IEnumerable 1[System.Int64], System.Collections.Generic.List 1[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?

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM