c# - Linq-To-Sql Dynamic-Where-Clauses 在 Framework 3.5 中甚至可能吗?

标签 c# linq-to-sql .net-3.5 where-clause

更新:它正在运行
我终于能够完成它。下面的答案中详细介绍了一个工作示例(我将能够在 2 天内划定)。


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

在过去的 3 天里,我一直在尝试在 DBML DataContext 上构建一个动态 where 子句。使用来自 questions posted here 的代码示例来自other sources还有...没有一个起作用!

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

  1. Predicate Builder在他们的网站上注意到 Framework 4.0。
  2. 一些 answers here讨论 4.0 中的等效 Invoke 版本(所以我在这里有一些希望)。
  3. ...我可以继续,但你明白了。

我真的很茫然,似乎在“捕获字符串”......我需要一些关于如何处理这个问题的合理建议。

原版有SOME Success但仅当:
唯一一次我有一个成功的“暗示”数据出现(所有 6178 行)但没有应用 WHERE CLAUSE缺少 WHERE CLAUSE 应用于 dataContext.GetCommand(query).CommandText< 中的 SQL 证明了这一点.

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

// VERSION 1:
public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }
    public static Expression<Func<T, bool>> StringLike<T>(Expression<Func<T, string>> selector, string pattern)
    {
        var predicate = PredicateBuilder.True<T>();
        var parts = pattern.Split('%');
        if (parts.Length == 1) // not '%' sign
        {
            predicate = predicate.And(s => selector.Compile()(s) == pattern);
        }
        else
        {
            for (int i = 0; i < parts.Length; i++)
            {
                string p = parts[i];
                if (p.Length > 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<QuickFindResult> QueryDocuments(string searchText, string customerSiteId, List<int> filterIds)
{
    var where = PredicateBuilder.True<vw_QuickFindResult>();

    var searches = new List<String>(searchText.Split(' '));
    searches.ForEach(productName =>
    {
        string like = productName.Replace('"', '%')
                                 .Replace('*', '%');

        where = PredicateBuilder.StringLike<vw_QuickFindResult>(x => x.DocumentName, like);
    });


    var results = DocumentCollectionService.ListQuickFind(where, null);

    // Do other stuff here...

    return results;
}
// VERSION 1:
public static List<vw_QuickFindResult> ListQuickFind(Expression<Func<vw_QuickFindResult, bool>> where, Expression<Func<vw_QuickFindResult, bool>> orderBy)
{
    var connectionString = GetConnectionString(ES_DOCUMENTS_CONNECTION_NAME);
    List<vw_QuickFindResult> results = null;

    using (HostingEnvironment.Impersonate())
    {
        using (var dataContext = new ES_DocumentsDataContext(connectionString))
        {
            IQueryable<vw_QuickFindResult> query = dataContext.vw_QuickFindResults;
            query = query.Where(where);

            results = query.ToList();
        }
    }

    return results;
}

其他版本 #2 失败:
并生成此错误:“无法在客户端使用方法‘Boolean Like(System.String, System.String)’;它仅用于转换为 SQL。”

// VERSION 2:
public List<QuickFindResult> QueryDocuments(string searchText, string customerSiteId, List<int> filterIds)
{
    Func<vw_QuickFindResult, bool> where = null;
    Func<string, Func<vw_QuickFindResult, bool>> buildKeywordPredicate = like => x => SqlMethods.Like(x.DocumentName, like);
    Func<Func<vw_QuickFindResult, bool>, Func<vw_QuickFindResult, bool>, Func<vw_QuickFindResult, bool>> buildOrPredicate = (pred1, pred2) => x => pred1(x) || pred2(x);

    // Build LIKE Clause for the WHERE
    var searches = new List<String>(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<vw_QuickFindResult> ListQuickFind(Expression<Func<vw_QuickFindResult, bool>> where, Expression<Func<vw_QuickFindResult, bool>> orderBy)
{
    var connectionString = GetConnectionString(ES_DOCUMENTS_CONNECTION_NAME);
    List<vw_QuickFindResult> 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;
}

最佳答案

您是否尝试过仅使用表达式类自己构建查询? 那里应该没有特别的问题。其实还是比较容易学的。 您可以编写一个示例查询,然后在调试中查看它是如何组成的:

Expression<Func<string, bool>> exp = (s) => s.Contains("your query");

然后简单看一下watch中的exp变量,就可以看出结构了。 这个特定的例子应该像这样组成:

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

关于c# - Linq-To-Sql Dynamic-Where-Clauses 在 Framework 3.5 中甚至可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8153260/

相关文章:

c# - 如何创建角色放入数据库?

c# - Linq-To-Sql 实体的接口(interface)

sql - 在有 in 子句的地方将 SQL 转换为 Linq

.net - NET中KeyedByTypeCollection的使用?

c# - 在 C# 中,如何在 SQL Server 中查找表的列名?

c# - 将 SPWeb 作为按值参数传递会导致内存泄漏吗?

c# - ListView 隐藏或折叠选定组

c# - 是否可以通用地实现这个接口(interface),以便它只能传递一个类型参数?

c# - 如何对来自 checkedlistbox C# 的所有未选中项目进行循环?

c# - 如何确保 Linq to Sql 不会覆盖或违反不可为 null 的数据库默认值?