Как сравнить значение поля в списке с другим значением в другом списке в предложении Where - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть список таблицы оценки сотрудников, в этой таблице есть поле TotalResult, значения в этом поле находятся в диапазоне от 1 до 10. Другая таблица Сегментация результатов имеет следующие столбцы:

Id int, Max double, Min double, Desc string

Давайтескажем, у меня есть эти данные для оценки сотрудника:

EmpId  EmpName   TotalResult
---  -------   -----------
1      Jaims     1.5
2      Johny     8.3
3      Moon      5.6
4      Michle    7
5      Mariam    9
6      Kamel     4

Значения сегментации результатов

Id   Max    Min   Desc
---  ---    ---   -----
1     3      1     ~ 30%
2     4      3     40%
3     5      4     50%
4     6      5     60%
5     7      6     70%
6     10     7     ~ 80%

Теперь у пользователя есть список с множественным выбором таблицы сегментации тарифов

enter image description here

если пользователь выбирает 70% и 40%, запрос должен показывать следующие оценки сотрудников:

EmpId  EmpName   TotalResult
-----  -------   -----------
3      Moon      5.6
6      Kamel     4
4      Michle    7

я написал этот код

if (rateSegIds != null)
{
    var rateSegs = _repositoryRateSeg.Query(x => rateSegId.Contains(x.Id)).ToList();

    if (rateSeg.Any())
    {
        foreach (var segmentation in rateSeg)
        {
            query = query.Where(x => x.TotalResult > segmentation.Min &&  x.TotalResult <= segmentation.Max);       
        }
    }
}
  • rateSegIds - это список целых чисел, содержащий выбор пользователя
  • rateSegs содержит записи из таблицы RateSegmataions согласно списку Ids
  • запрособъект запроса EmployeeAppraisal таблица

Этот код работает, только если пользователь выбирает одно значение из списка, если он / она выбирает несколько значений, запрос ничего не даст.

Поскольку он действует как «И», он должен действовать как «ИЛИ», но я не знал, как писать.

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Перекрестное соединение может быть одним из решений, таких как:

    var rateSegIds = new int[] {2, 5}; //40% and 70%

    var result = from emp in EmployeeAppraisals
                 from segment in Segments.Where(x => rateSegIds.Contains(x.Id))
                 where emp.Total >= segment.Min && emp.Total <= segment.Max
                 select emp;
0 голосов
/ 12 февраля 2019

Это было то, что давало мне некоторое время назад, и вопрос только побудил меня немного вникнуть в это..Where() добавит условия, но, как вы заметили, с операцией AndAlso.Чтобы заставить EF и Linq динамически поддерживать условие OrElse, вам нужно немного перестроить дерево выражений или условия вместе.Престижность ответа пользователя user743382 на Исключение с использованием методов выражений OrElse и AndAlso

Вам понадобится пара классов, чтобы позволить посетителю выражения выстроить параметры для нескольких выражений, которые будут объединяться в единое целое,Что-то вроде:

private Expression<Func<EmployeeAppraisal, bool>> buildFilterExpression(IEnumerable<Segment> segments)
{
    Expression<Func<EmployeeAppraisal, bool>> exp = c => false;

    foreach (var segment in segments)
    {
        Expression<Func<EmployeeAppraisal, bool>> filter = x => x.TotalResult >= segment.Min && x.TotalResult <= segment.Max;
        exp = Expression.Lambda<Func<EmployeeAppraisal, bool>>(Expression.OrElse(exp.Body,
            new ExpressionParameterReplacer(filter.Parameters, exp.Parameters).Visit(filter.Body)), exp.Parameters);
    }

    return exp;
}

private class ExpressionParameterReplacer : ExpressionVisitor
{
    public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
    {
        ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
        for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
            ParameterReplacements.Add(fromParameters[i], toParameters[i]);
    }

    private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements
    {
        get;
        set;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        ParameterExpression replacement;
        if (ParameterReplacements.TryGetValue(node, out replacement))
            node = replacement;
        return base.VisitParameter(node);
    }
} 

Тогда в вашем выражении EF Linq:

var rateSegs = _repositoryRateSeg.Query(x => rateSegId.Contains(x.Id)).ToList();

if (rateSeg.Any())
    query = query.Where(buildFilterExpression(rateSegs));

ExpressionParameterReplacer и вспомогательные классы объединяют ИЛИ вместе с различными телами выражений и гарантируют, что они связаны стот же параметр выражения, чтобы Linq правильно оценивал их как одно выражение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...