2010-09-23 53 views
1

我一直怀着极大的兴趣converstaion这里:的Linq:动态查询敷设渠道:查询移动到客户端

Construct Query with Linq rather than SQL strings

与关于构建表达式树,甚至表名是动态的。

为了实现这一目标,我创建了一个扩展方法,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语句,而不是确定客户端

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

干杯。

+0

你在那里有'Compile'的事实应该有一个大的红色标志来表明它不能在数据库服务器上运行。 – Gabe 2010-09-23 20:46:16

回答

1

最大的问题是您要将表达式树转换为委托。看看Queryable.Where的签名 - 它在表达式树中表示,而不是代表。所以你实际上而不是呼叫Enumerable.Where。这就是为什么你需要事后致电AsQueryable--但这在这里没有足够的魔法。它并没有真正把它放回到“内部表达树”的土地上,因为你仍然有代表在那里。现在是包装在表达式树中,但是您已经丢失了里面发生了什么的细节。

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

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

我爽快地承认,我没有看过你的代码的其余部分,所以有可能是其他的东西怎么回事......但是这就是核心位。您需要一个强类型表达式树(因此调用通用表格Expression.Lambda),然后您可以将其传递到Queryable.Where。给它一个:)

+0

好吧,我删除了编译部分,所以现在的代码如下所示: – donundeen 2010-09-23 20:52:21

+0

Giggity!这就是诀窍!当你们很快! – donundeen 2010-09-23 20:55:26