C# 将方法转换为用于查询的Linq表达式

C# 将方法转换为用于查询的Linq表达式,c#,linq,linq-to-sql,expression-trees,C#,Linq,Linq To Sql,Expression Trees,在我们的应用程序中,我们希望为数据库中的各种条件提供标准方法。例如,我们有不同类型的事务,我们希望创建标准方法,以便在其他查询中检索它们。但是,这给了我们一个错误: 方法“”不支持到SQL的转换 该方法可能如下所示: public static bool IsDividend(this TransactionLog tl) { return tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobTyp

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

方法“”不支持到SQL的转换

该方法可能如下所示:

public static bool IsDividend(this TransactionLog tl)
{
    return tl.SourceTypeID == (int)JobType.Dividend || tl.SourceTypeID == (int)JobType.DividendAcct;
}
var dividends = ctx.TransactionLogs.Where(tl => ToExpression(tl.IsDividend));
用作:

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 to SQL。

对于我来说,拥有包含表达式的静态属性似乎很好

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

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(x.IsDividend());
但这两种方法都不适用于
var-dividens=ctx.TransactionLogs.Where(x=>x.IsDividend())x=>x.IsDividend()
本身是一个表达式树,您的数据库提供程序无法将“IsDivided”转换为SQL语句


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

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

尝试使用扩展方法,如:

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


在这种情况下,可以使用Func。Linq在这方面做得很好。 下面是在Linq查询中使用Func的简单示例。请随意修改和使用

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

表达式可以很容易地转换为方法(这就是它们的设计目的),但相反的操作相当于反编译。另一种选择是创建扩展方法,创建数据的虚拟视图。使用您的
ctx
对象,并在其上创建一个只返回红利的扩展方法
public static类ctxObjectTypeExtension{public static IQueryable distributions(this ctxobjecttype ctx){return ctx.TransactionLogs.Where(tl=>tl.SourceTypeID==(int)JobType.distribution | | tl.SourceTypeID==(int)JobType.DividendAcct));}
调用like
var distributions=ctx.distributions()这将无法将查询转换为SQL,正如问题所问。您是对的,直接针对SQL它不会,但当您执行select ToList()时,它工作得非常好,并且与其他可能的解决方案具有相同的性能影响。不,它工作得并不完美。它根本不在数据库中执行查询。它的性能非常差,因为这意味着将数据库的全部内容拉入内存,然后在内存中对其进行操作,其结果是它可能完全无法工作(内存可能不足,可能有太多数据无法从数据库中提取,很容易导致操作超时等).
var dividends=db.TransactionLogs.OnlyDividends();
var dividends=db.TransactionLogs.OnlyDividends().OrderBy(...);
Func<int,bool> isDivident = x => 3==x;
int[] values = { 3, 7, 10 };
var result = values.Select (isDivident );