1

我一直非常感兴趣地关注这里的对话:

使用 Linq 而不是 SQL 字符串构造查询

关于构建即使表名也是动态的表达式树。

为此,我创建了一个扩展方法 addWhere,如下所示:

static public IQueryable<TResult> addWhere<TResult>(this IQueryable<TResult> query, string columnName, string value)
{
    var providerType = query.Provider.GetType();
    // Find the specific type parameter (the T in IQueryable<T>)
    var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
    var tableType = iqueryableT.GetGenericArguments()[0];
    var tableName = tableType.Name;
    var tableParam = Expression.Parameter(tableType, tableName);
    var columnExpression = Expression.Equal(
        Expression.Property(tableParam, columnName),
        Expression.Constant(value));
    var predicate = Expression.Lambda(columnExpression, tableParam);
    var function = (Func<TResult, Boolean>)predicate.Compile();
    var whereRes = query.Where(function);
    var newquery = whereRes.AsQueryable();
    return newquery;
}

[感谢 Timwi 提供该代码的基础]

哪个在功能上有效。

我可以打电话:

query = query.addWhere("CurUnitType", "ML 15521.1");

它在功能上等同于:

query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));

即,返回的行是相同的。

但是,我开始查看 sql 日志,并注意到以下行:

query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));

生成的查询是:

SELECT (A bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
WHERE [t0].[CurUnitType] = @p0

而当我使用这条线时

query = query.addWhere("CurUnitType", "ML 15521.1");

生成的查询是:

SELECT (the same bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]

因此,比较现在发生在客户端,而不是被添加到 sql 中。

显然,这不是那么热。

老实说,我主要是从 Timwi 的(略有不同的)示例中剪切并粘贴了 addWhere 代码,所以其中一些内容超出了我的想象。我想知道我是否可以对此代码进行任何调整,因此表达式被转换为 SQL 语句,而不是在客户端确定

感谢您花时间阅读本文,我欢迎任何可以帮助我的评论、解决方案、链接等。当然,如果我通过其他方式找到解决方案,我会在这里发布答案。

干杯。

4

1 回答 1

1

最大的问题是您将表达式树转换为委托。看看Queryable.Where- 它的签名是在表达式树中表达的,而不是代表。所以你实际上是在打电话Enumerable.Where。这就是为什么你需要AsQueryable事后打电话的原因——但这在这里没有足够的魔力。它并没有真正将其放回“仅在内部表达树”的领域,因为您仍然将委托放在那里。它现在被包裹在一个表达式树中,但是你已经丢失了里面发生的事情的细节。

我怀疑你想要的是这样的:

var predicate = Expression.Lambda<Func<TResult, Boolean>>
      (columnExpression, tableParam);
return query.Where(predicate);

我欣然承认我还没有阅读您的其余代码,因此可能还有其他事情发生......但这是核心部分。您需要一个强类型表达式树(因此调用 的通用形式Expression.Lambda),然后您可以将其传递给Queryable.Where. 试一试 :)

于 2010-09-23T20:39:19.767 回答