Предикат Linq для сопоставления объектов из многих слоев вложенных коллекций

#c# #linq

#c# #linq

Вопрос:

У меня есть:

 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; }
    ....
}
  

Мне нужно написать конструктор предикатов, который фильтрует те PaymentCode , которые можно найти из списка строк.
Это то, что я сделал, но он по-прежнему возвращает все результаты:

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

Редактировать:

универсальный конструктор предикатов:

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

Как применяется предикат:

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

Комментарии:

1. And() насколько я вижу, это не стандартное расширение LINQ. Какой тип predicate и что predicate.And(...) делает?

2. @Corey Я добавил РЕДАКТИРОВАНИЕ, чтобы добавить универсальный конструктор предикатов, и метод And() исходит из этого

3. Ваше And() расширение выглядит нормально. Остается сам предикат. Вы показываете, как он составлен, но не как он применяется. Где-то вам придется вызывать Where(...) для фильтрации коллекции. Не могли бы вы показать этот код, пожалуйста?

4. Вы хотите просто узнать, есть ли какая-либо строка, содержащая эти коды платежей, или вы хотите иметь эти объекты? Если это так, вам нужно Where предложение. А затем возврат a bool в предикате не имеет особого смысла

5. @Link Я хочу отфильтровать объект Payment , который PaymentCode соответствует условию