C# 有没有办法在linq查询中参数化方法?

C# 有没有办法在linq查询中参数化方法?,c#,linq,linq-to-sql,C#,Linq,Linq To Sql,在我使用LINQtoSQL的应用程序中,用户可以搜索文本。可以在搜索表达式的开头和/或结尾使用asterix(*)。现在的代码是: var search = SearchTextBox.Text.Trim(); bool filterStartsWith = false, filterEndsWith = false; if (!string.IsNullOrEmpty(search)) { filterStartsWith = search.EndsWith("*"); fil

在我使用LINQtoSQL的应用程序中,用户可以搜索文本。可以在搜索表达式的开头和/或结尾使用asterix(*)。现在的代码是:

var search = SearchTextBox.Text.Trim();
bool filterStartsWith = false, filterEndsWith = false;
if (!string.IsNullOrEmpty(search))
{
    filterStartsWith = search.EndsWith("*");
    filterEndsWith = search.StartsWith("*");
    if (filterStartsWith) search = search.Substring(0, search.Length - 1);
    if (filterEndsWith) search = search.Substring(1);

    if (filterStartsWith)
    {
        if (filterEndsWith)
        {
            query = query.Where(item => item.Omschrijving.Contains(search));
        }
        else
        {
            query = query.Where(item => item.Omschrijving.StartsWith(search));
        }
    }
    else
    {
        if (filterEndsWith)
        {
            query = query.Where(item => item.Omschrijving.EndsWith(search));
        }
        else
        {
            query = query.Where(item => item.Omschrijving == search);
        }
    }
}
然而,我想概括一下,因为这种搜索在更多的地方发生。此外,对于某些表,这应该发生在多个列上。有什么想法吗


我将Visual Studio 2010与.NET Framework 4.0结合使用。

您可以使用策略模式。您将有4个基于“search”值的策略,使用“bool CanHandle(search)”方法,一个工厂创建一个策略列表,您的程序将调用一个客户端创建一个新工厂,调用一个方法“BuildQuery(search)”,该方法执行使用CanHandle方法找到的正确策略,并返回一个查询值


您可以使用动态构建的表达式

下面是一个在多列上实现StartWith的示例代码(可能无法编译,我直接在stackoverflow中键入它)-只需添加对其他方法的支持

这段代码适用于所有linq到sql查询,假设“columnsToSearch”总是引用字符串属性

IQueryable myQuery = ... your query you want to filter ...;
string searchWhat = "text to search";
bool startsWith;
Expression condition = null;
var p = Expression.Parameter(myQuery.ElementType,"x");
foreach (string column in columnsToSearch)
{
    if (startsWith)
    {
        var myCondition = Expression.Call(Expression.PropertyOrField(p, column),
                          typeof (string).GetMethod("StartsWith"),
                          Expression.Constant(searchWhat));
        if (condition == null)
            condition = myCondition;
        else
            condition = Expression.OrElse(condition, myCondition);
     }
 }
 var newQuery = Expression.Call(typeof (Queryable).GetMethod("Where"), myQuery.Expression, Expression.Lambda(condition, p));
 var myQueryFiltered = myQuery.Provider.CreateQuery(newQuery);
简而言之,如果你有疑问
myRepository.Where(t=>t.Mycondition)
此代码将生成一个新的查询,如
myRepository.Where(t=>t.Mycondition.Where(t=>t.Field1.StartsWith(“a”)| t.Field2.StartWith(“a”)
(当然取决于您给它的列)

然后,您所要做的就是将“myQueryFiltered”转换为IEnumerable或IQueryable,以便执行它并获得过滤结果:)

您可以尝试以下方法:

static IQueryable<T> WhereColumnContains<T>(this IQueryable<T> source, Expression<Func<T, string>> selector, string search)
{
    if (string.IsNullOrWhiteSpace(search))
    {
        return source;
    }

    Expression<Func<T, bool>> expression;

    search = search.Trim();

    var filterStartsWith = search.EndsWith("*");
    var filterEndsWith = search.StartsWith("*");

    if (filterEndsWith) search = search.Substring(1);

    if (filterStartsWith)
    {
        search = search.Substring(0, search.Length - 1);

        if (filterEndsWith)
        {
            var parameter = Expression.Parameter(typeof(T), "parameter");

            expression = Expression.Lambda<Func<T, bool>>(
                Expression.Call(Expression.Invoke(selector, parameter), typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant(search)),
                parameter);
        }
        else
        {
            var parameter = Expression.Parameter(typeof(T), "parameter");

            expression = Expression.Lambda<Func<T, bool>>(
                Expression.Call(Expression.Invoke(selector, parameter), typeof(string).GetMethod("StartsWith", new[] { typeof(string) }), Expression.Constant(search)),
                parameter);
        }
    }
    else
    {
        if (filterEndsWith)
        {
            var parameter = Expression.Parameter(typeof(T), "parameter");

            expression = Expression.Lambda<Func<T, bool>>(
                Expression.Call(Expression.Invoke(selector, parameter), typeof(string).GetMethod("EndsWith", new[] { typeof(string) }), Expression.Constant(search)),
                parameter);
        }
        else
        {
            var parameter = Expression.Parameter(typeof(T), "parameter");

            expression = Expression.Lambda<Func<T, bool>>(
                Expression.Equal(Expression.Invoke(selector, parameter), Expression.Constant(search)),
                parameter);
        }
    }

    return source.Where(expression);
}

我想这可能是我需要的。是否也可以使用Or关系搜索多个列?我的Lambda知识有些生疏;-)@doekman的AND关系总是比较容易的,当然,您可以将调用链接在一起:-),但是使用
Expression.OrElse(…)
肯定可以使用OR。恼人的一点是弄清楚如何传入参数。如果你不介意的话,我将把它作为练习留给读者。我希望我的回答能为你提供足够的线索。谢谢你的提示。我没有想到Expression.OrElse。我想我只是用
params
传递它们。是否有一个
search
值应用于多个列?这应该很容易。正如您所说,只需将seach作为第一个参数传递,然后
params
表达式。如果对每一列(n列,n个值)使用不同的
搜索
值,则可能会出现混乱。对所有列进行相同的搜索,但现在
。where
方法需要一个
表达式
,但
。OrElse
提供了一个二进制表达式。。。
query = query.WhereColumnContains(item => item.Omschrijving, search);