在Framework 3.5中Linq-To-Sql动态Where子句是否可能?

更新:现在正在工作
我终于完成了它。 下面的答案中详述了一个工作示例(我将在2天内进行标记)。


以下所有内容都是原始问题的一部分

在过去的3天里,我一直在尝试使用来自此处其他来源的 问题的代码示例在DBML DataContext上构建一个dynamic-where子句…… 没有一个有效

由于以下原因,我开始怀疑在Framework 3.5下是否甚至可能使用它:

  1. Predicate Builder在其网站上注明了Framework 4.0。
  2. 这里的一些答案谈论4.0中的一个等效的Invoke版本(所以我在这里有一些希望)。
  3. ……我可以继续,但你明白了。

我真的很茫然,似乎在“抓住弦乐”……我需要一些关于如何处理这个问题的合理建议。

原始版本取得了一些成功,但仅限于:
数据出现的唯一时间我得到了“成功”(所有6178行),但没有应用WHERE CLAUSE 。 这可以通过在dataContext.GetCommand(query).CommandText找到的SQL 没有应用任何WHERE CLAUSE dataContext.GetCommand(query).CommandText

其他版本#1失败:
并生成此错误:“方法”System.Object DynamicInvoke(System.Object [])’没有受支持的SQL转换。“

 // VERSION 1: public static class PredicateBuilder { public static Expression<Func> True() { return f => true; } public static Expression<Func> False() { return f => false; } public static Expression<Func> Or(this Expression<Func> expr1, Expression<Func> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda<Func>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression<Func> And(this Expression<Func> expr1, Expression<Func> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda<Func>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression<Func> StringLike(Expression<Func> selector, string pattern) { var predicate = PredicateBuilder.True(); var parts = pattern.Split('%'); if (parts.Length == 1) // not '%' sign { predicate = predicate.And(s => selector.Compile()(s) == pattern); } else { for (int i = 0; i  0) { if (i == 0) { predicate = predicate.And(s => selector.Compile()(s).StartsWith(p)); } else if (i == parts.Length - 1) { predicate = predicate.And(s => selector.Compile()(s).EndsWith(p)); } else { predicate = predicate.And(s => selector.Compile()(s).Contains(p)); } } } } return predicate; } } // VERSION 1: public List QueryDocuments(string searchText, string customerSiteId, List filterIds) { var where = PredicateBuilder.True(); var searches = new List(searchText.Split(' ')); searches.ForEach(productName => { string like = productName.Replace('"', '%') .Replace('*', '%'); where = PredicateBuilder.StringLike(x => x.DocumentName, like); }); var results = DocumentCollectionService.ListQuickFind(where, null); // Do other stuff here... return results; } // VERSION 1: public static List ListQuickFind(Expression<Func> where, Expression<Func> orderBy) { var connectionString = GetConnectionString(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionString)) { IQueryable query = dataContext.vw_QuickFindResults; query = query.Where(where); results = query.ToList(); } } return results; } 

其他版本#2失败:
并生成此错误:“方法”布尔类似(System.String,System.String)’不能在客户端上使用;它仅用于转换为SQL。“

 // VERSION 2: public List QueryDocuments(string searchText, string customerSiteId, List filterIds) { Func where = null; Func<string, Func> buildKeywordPredicate = like => x => SqlMethods.Like(x.DocumentName, like); Func<Func, Func, Func> buildOrPredicate = (pred1, pred2) => x => pred1(x) || pred2(x); // Build LIKE Clause for the WHERE var searches = new List(searchText.Split(' ')); searches.ForEach(productName => { string like = productName.Replace('"', '%') .Replace('*', '%'); where = (where == null) ? buildKeywordPredicate(like) : buildOrPredicate(where, buildKeywordPredicate(like)); }); var results = DocumentCollectionService.ListQuickFind(where, null); // Do other stuff here... return results; } // VERSION 2: public static List ListQuickFind(Expression<Func> where, Expression<Func> orderBy) { var connectionString = GetConnectionString(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionString)) { var query = dataContext.vw_QuickFindResults.AsEnumerable(); query = query.Where(where); results = query.ToList(); } } return results; } 

您是否仅使用Exression类尝试自己构建查询? 那里应该没有特别的问题。 它实际上相对容易学习。 您可以编写示例查询,然后在调试中查看它的组成方式:

 Expression> exp = (s) => s.Contains("your query"); 

然后只需查看手表中的exp变量,即可看到结构。 这个特殊的例子应该像这样组成:

 Expression constant = Expression.Constant("your query"); Expression p = Expression.Param(typeof(string); Expression contains = Expression.Call(p, "Contains", constant); Expression> lambda = Expression.Lamba(contains, p); // Now you can send this to your ORM 

我可以告诉你,我在2010年初使用LinqKit和PredicateBuilder,使用.Net 3.5,EF 1.0和EF Poco Adapter。 当时,LinqKit是为Net 3.5编译的

也许如果你问作者(Albahari),他可以发送给你(或在网站上发布)3.5版本。 我不再拥有它,因为它在我旧工作场所的项目中,而且我无法访问它们。

作为旁注,我觉得在将近2年的.Net 4出现后,你的痛苦被迫与3.5一起工作。

这是正确的ASWER
这是需要它的人的工作版本。 问题是事物的组合。 第一个是以下行设置为True

var where = PredicateBuilder.True();

它应该是False ……

var where = PredicateBuilder.False();

我不知道为什么……但也需要其他改变。

 public static class PredicateBuilder { public static Expression> True() { return f => true; } public static Expression> False() { return f => false; } public static Expression> Or(this Expression> expr1, Expression> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); } public static Expression> And(this Expression> expr1, Expression> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); return Expression.Lambda>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); } } public List QueryDocuments(string searchText, string customerSiteId, List filterIds) { var wildCards = new string[] { "*", "\"" }; var where = PredicateBuilder.False(); var searches = new List(searchText.Split(' ')); // TODO: <-- If more complex searches are needed we'll have to use RegularExpressions // SEARCH TEXT - WHERE Clause searches.ForEach(productName => { Boolean hasWildCards = (productName.IndexOfAny(new char[] { '"', '*' }) != -1); if (hasWildCards) { Int32 length = productName.Length; if (length > 1) { string like = productName.Replace("%", "") .Replace("*", ""); string first = productName.Substring(0, 1); string last = productName.Substring(length - 1); // Contains if (wildCards.Contains(first) && wildCards.Contains(last)) where = where.Or(p => p.DocumentName.Contains(like) || p.DocumentTitle.Contains(like)); // EndsWith else if (wildCards.Contains(first)) where = where.Or(p => p.DocumentName.EndsWith(like) || p.DocumentTitle.EndsWith(like)); // StartsWith else if (wildCards.Contains(last)) where = where.Or(p => p.DocumentName.StartsWith(like) || p.DocumentTitle.StartsWith(like)); // Contains (default) else where = where.Or(p => p.DocumentName.Contains(like) || p.DocumentTitle.Contains(like)); } else // Can only perform a "contains" where = where.Or(p => p.DocumentName.Contains(productName) || p.DocumentTitle.Contains(productName)); } else // Can only perform a "contains" where = where.Or(p => p.DocumentName.Contains(productName) || p.DocumentTitle.Contains(productName)); }); // FILTER IDS - WHERE Clause var filters = GetAllFilters().Where(x => filterIds.Contains(x.Id)).ToList(); filters.ForEach(filter => { if (!filter.IsSection) where = where.And(x => x.FilterName == filter.Name); }); var dataSource = DocumentCollectionService.ListQuickFind(where); var collection = new List(); // Other UNRELATED stuff happens here... return collection; } public static List ListQuickFind(Expression> where) { var connectionString = GetConnectionString(ES_DOCUMENTS_CONNECTION_NAME); List results = null; using (HostingEnvironment.Impersonate()) { using (var dataContext = new ES_DocumentsDataContext(connectionString)) { var query = dataContext.vw_QuickFindResults.Where(where).OrderBy(x => x.DocumentName).OrderBy(x => x.DocumentTitle); results = query.ToList(); } } return results; }