【问题标题】:Use result of entity's method for filtering with lambda expression or linq query使用实体方法的结果通过 lambda 表达式或 linq 查询进行过滤
【发布时间】:2011-08-08 21:24:42
【问题描述】:

我想根据使用其属性的函数的结果过滤我的实体。

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

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 无法识别方法 -----,并且此方法无法转换为商店表达式。

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

编辑:这是“DoMath”函数的真实代码(没有 cmets,因为它们不是英文的):

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坐标。我正在使用它来计算给定值适合模糊集合的程度。

【问题讨论】:

  • 您只需要解析该 DoMath 方法,然后缓慢但肯定地得出 A、B、C 和 D 的值,这些值不会产生您正在寻找的值,并将它们排除在您对数据库的 linq 查询,然后将剩余的内容拉入内存(通过使用 AsEnumerable)并通过在第二个 lambda 中实际调用 DoMath 来过滤其余部分

标签: c# entity-framework lambda linq-to-entities


【解决方案1】:

Entity Framework 的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);

【讨论】:

  • 打败我。好答案。通常我也会说另一种选择是注册一个可以在数据库上调用的 SQL 函数,但我认为对于数学处理来说这将是一个糟糕的选择。
  • @StriplingWarrior - 我觉得他的实际 DoMath 方法更复杂;但是,如果真的像他描述的那么简单,那么是的,你说的
  • 谢谢,我正在处理你的答案,所以请稍等 :) 当有人试图找到更简单的解决方案时,我将使用 DoMatg 函数编辑我的 Q。
  • 谢谢,您设置 AsEnumerable() 的解决方案适用于我的场景,因为我不会有很多记录(现在大约 30 条)。 +1 我要等一会儿才能关闭它。
  • 没问题 - 很高兴我能帮上忙!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多