将方法转换为Linq表达式以进行查询

时间:2015-03-12 13:05:31

标签: c# linq linq-to-sql expression-trees

在我们的应用程序中,我们希望为数据库中的各种条件提供标准方法。例如,我们有不同类型的事务,我们希望创建标准方法以在其他查​​询中检索它们。但是,这给了我们错误:

  

方法''没有受支持的SQL翻译

该方法可能如下所示:

public static bool IsDividend(this TransactionLog tl)
{
    return tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobType.DividendAcct;
}

如此使用:

var dividends = ctx.TransactionLogs.Where(x => x.IsDividend());

当然,如果我将逻辑从IsDividend()复制到Where子句中,这样可以正常工作,但我最终会在很多地方复制这个逻辑,如果逻辑发生变化则难以追踪。

我认为如果我将它转换为这样的表达式,它会起作用,但这不是一个可以使用方法的设置:

public Expression<Func<TransactionLog, bool>> IsDividend = tl => tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobType.DividendAcct;

var dividends = ctx.TransactionLogs.Where(IsDividend);

有没有办法迫使Linq将方法评估为表达式?或者转换&#34;转换&#34;该方法调用linq查询中的表达式?像这样:

var dividends = ctx.TransactionLogs.Where(tl => ToExpression(tl.IsDividend));

我们在我们的应用程序中使用Linq-to-SQL。

4 个答案:

答案 0 :(得分:1)

包含表达式的静态属性对我来说似乎很好。

使其与Method一起使用的唯一方法是创建一个返回此表达式的方法,然后在其中调用它:

public class TransactionLog 
{
    Expression<Func<TransactionLog, bool>> IsDividend() {
        Expression<Func<TransactionLog, bool>> expression = tl => tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobType.DividendAcct;
        return expression;
    }
}

public class TransactionLogExtension
{
    Expression<Func<TransactionLog, bool>> IsDividend(this TransactionLog log) {
        Expression<Func<TransactionLog, bool>> expression = tl => tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobType.DividendAcct;
        return expression;
    }
}

并通过

使用它
var dividends = ctx.TransactionLogs.Where(TransactionLog.IsDividend());

或作为扩展方法

var dividends = ctx.TransactionLogs.Where(x.IsDividend());

但它都不适用于var dividends = ctx.TransactionLogs.Where(x => x.IsDividend());,因为x => x.IsDividend();本身就是一个表达式树,而您的数据库提供商无法翻译&#34; IsDividend&#34;进入SQL语句。

但是其他两个选项至少允许您传入参数(如果将表达式存储为实例或静态属性,则这些参数不起作用)。

答案 1 :(得分:0)

我认为LINQ to SQL并不完全支持常见和内置函数。 (至少EF没有这样做)。而且 - 当它处理用户定义的方法时。我预测,除非在枚举后调用它(ToList或类似方法),否则带表达式的变体将与使用方法调用的变量一样下降。我建议保持1)存储过程在服务器之间的平衡,2)在C#中Where子句中硬编码的常见条件,3)在C#中生成表达式树。所有这些都是相对复杂的,当然(在我看来,没有简单而通用的解决方案)。

答案 2 :(得分:0)

尝试使用扩展方法,如下所示:

public static class TransactionLogExtensions {
    public static IQueryable<TransactionLog> OnlyDividends(this IQueryable<TransactionLog> tl)
    {
        return tl.Where(t=>t.SourceTypeID == (int)JobType.Dividend || t.SourceTypeID == (int)JobType.DividendAcct);
    }
}

这样称呼:

var dividends=db.TransactionLogs.OnlyDividends();

var dividends=db.TransactionLogs.OnlyDividends().OrderBy(...);

答案 3 :(得分:-1)

对于此方案,您可以使用Func。 Linq对那些非常好。 以下是在Linq查询中使用Func的简单示例。随意修改和使用。

Func<int,bool> isDivident = x => 3==x;
int[] values = { 3, 7, 10 };
var result = values.Select (isDivident );