Linq predicate to match objects from many layers of nested collections

Viewed 139

I have:

public class TotalPeriod
{
    public ICollection<SubPeriod> SubPeriods { get; set; }
    ....
}

public class SubPeriod
{
    public ICollection<SmallerSubPeriod> SmallerSubPeriods { get; set; }
    ....
}

public class SmallerSubPeriod
{
    public Payment Payment { get; set; }
    ....
}

public class Payment
{
    public string PaymentCode { get; set; }
    ....
}

I need to write a predicate builder that filters the PaymentCode which can be found from a list of string. This is what I have done, but it still returns all results:

var predicate = PredicateBuilder.True<TotalPeriod>();
...// other logic
var paymentCodes = new HashSet<string>();
... // other logic to successfully get list of paymentCodes from UI
if(paymentCodes.Any())
{
    predicate = predicate.And(entity => entity.SubPeriods.Any(e => e.SmallerSubPeriods.Any(e => paymentCodes.Contains(e.Payment.PaymentCode))));
}

EDIT:

generic predicate builder:

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
        return Expression.Lambda<Func<T, bool>> (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }
}

How the predicate is applied:

public async Task<ApiResponse<T>> GetManyAsync<T>(Expression<Func<TDAL, bool>> predicate, ICollection<string> includes = null) where T : class
{
    try {
            var expression = Expression.Convert(predicate.Body, typeof(bool));
            var lambda = Expression.Lambda<Func<TDAL, bool>>(expression, predicate.Parameters);
            using var dbContext = GetDatabaseContext();
            var entities = await dbContext.Set<TDAL>().Where(lambda).AsNoTracking().ToArrayAsync();
            ... // other logic
    } catch (Exception e) {
        return DataProviderException.CatchException<T>(e);
    }
}
0 Answers
Related