使用entity's方法的结果进行lambda表达式或linq查询的过滤

本文关键字:lambda 表达式 过滤 查询 linq 结果 entity 方法 使用 | 更新日期: 2023-09-27 17:50:40

我想过滤我的实体取决于一个函数的结果与他们的属性工作。

ie。我得到了这样的实体:

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不识别-----方法,该方法不能转换为store表达式。

有可能使它像这样工作吗?
我在定制lambda表达式和使用委托方面的技能相当差,所以我想得到一些帮助。

编辑:这是'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坐标。我用它来计算给定值在模糊集合中的适合程度。

使用entity's方法的结果进行lambda表达式或linq查询的过滤

实体框架的Where期待一个表达式树,这将被转换成一个t-sql语句。不幸的是,没有从你的DoMath方法到t-sql的转换,所以你必须把结果拉到内存中,然后调用Where,因为你有它。原因是,一旦你的结果在内存中,LINQ方法工作在标准委托,而不是表达式树,所以没有限制什么可以放在那里

要做到这一点,只需在Where前面添加一个AsEnumerable() -当然,这会将整个表拉入内存,所以只有在它相当小的情况下才这样做

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