Использовать результат метода сущности для фильтрации с помощью лямбда-выражения или запроса linq - PullRequest
3 голосов
/ 19 апреля 2011

Я бы хотел отфильтровать свои объекты в зависимости от результата работы функции с их свойствами.

т.е.Я получил объект, подобный этому:

public class Lorem
{
    public int A {get;set;}
    public int B {get;set;}
    public int C {get;set;}

    public double DoMath(int externalValue)
    {
        // real implementation is longer and more complex

        if(A==B) {
          // some calculations
          return 0.2;
        }
        if(B==C) {
          // some calculations
          return 0.9;
        }
        else return 0;
    }
}

Теперь я запрашиваю объекты, и я хотел бы получить только те, у которых DoMath> 0.

// simplified scenario for example purpose
int someValue = 95;
// working with Entity Framework 4.1 Code First
var filtered = db.Lorems.Where(x=>x.DoMath(someValue) > 0);

Я получаю эту ошибку:
LINQ to Entities не распознает метод -----, и этот метод нельзя преобразовать в выражение хранилища.

Можно ли заставить его работать так?
Мои навыки в настройке лямбда-выражений и работе с делегатами довольно скудны, поэтому я хотел бы получить некоторую помощь.

Редактировать: вот эта функция «DoMath» работает с реальным кодом (без комментариев, потому что они нена английском):

public double VypocitejPrislusnost(int value)
{
    if (A == B)
    {

        if (value <= C)
        {
            return 1;
        }
        if (value > D)
        {
            return 0;
        }
        else
        {
            double b = D - C;
            double tangens = Math.Tan(1 / b);

            double a = tangens * (D - value);

            return Math.Round(a, 2);
        }
    }

    if (C == D)
    {

        if (value >= B)
        {
            return 1;
        }
        if (value <= A)
        {
            return 0;
        }
        else
        {
            double b = B - A;
            double tangens = Math.Tan(1 / b);

            double a = tangens * (value - A);

            return Math.Round(a, 2);
        }
    }

    else
    {
        if (value >= B && value <= C)
        {
            return 1;
        }
        if (value <= A || value >= D)
        {
            return 0;
        }
        if (value > A && value < B)
        {
            double b = B - A;
            double tangens = Math.Tan(1 / b);

            double a = tangens * (value - A);

            return Math.Round(a, 2);
        }
        if (value > C && value < D)
        {
            double b = D - C;
            double tangens = Math.Tan(1 / b);

            double a = tangens * (D - value);

            return Math.Round(a, 2);
        }
        else
        {
            return 0;
        }
    }
}

В основном он вычисляет координату y в треугольнике в различных сценариях.Я использую это для подсчета того, насколько данное значение вписывается в нечеткое множество.

1 Ответ

9 голосов
/ 19 апреля 2011

Entity Framework Where ожидает дерево выражений, которое будет преобразовано в оператор t-sql.К сожалению, нет перевода из вашего DoMath метода в t-sql, поэтому вам придется записать результаты в память, и затем вызовите Where, как у вас есть.Причина в том, что, как только ваши результаты находятся в памяти, методы LINQ работают со стандартными делегатами, а не с деревьями выражений, поэтому нет никаких ограничений на то, что можно поместить туда

Для этого просто добавьте AsEnumerable()перед Where - конечно, это сведет всю вашу таблицу в память, поэтому делайте это только в том случае, если она достаточно мала

var filtered = db.Lorems.AsEnumerable().Where(x => x.DoMath(someValue) > 0);

Конечно, если вы можете определить некоторые основные обстоятельства, при которых ваш DoMath будет не больше 0, вы можете отфильтровать эти результаты заранее, используя дерево выражений.Это урезает результаты, поступающие из базы данных.Вы можете затем отфильтровать все остальное в памяти.Я понятия не имею, что делает ваш метод DoMath (вы подразумеваете, что он сложнее, чем то, что указано в вашем вопросе), но гипотетически что-то подобное должно работать:

var filtered = db.Lorems
                 .Where(x => x.A < 10 && x.B != x.C)
                 .AsEnumerable() 
                 .Where(x => x.DoMath(someValue) > 0);
...