[英]Is there a way to parameterize method in a linq query?
In my application with Linq to SQL, the user can search for text. 在我使用Linq to SQL的应用程序中,用户可以搜索文本。 An asterix (*) can be used at the beginning and/or end of the search expression.
可以在搜索表达式的开头和/或结尾使用星号(*)。 The code now is this:
代码现在是这样的:
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);
}
}
}
However, I want to generalize this, because this kind of search happens on more places. 但是,我想概括一下,因为这种搜索发生在更多的地方。 Also, some tables, this should happen on more than one column.
此外,一些表,这应该发生在多个列上。 Any ideas?
有任何想法吗?
I use Visual Studio 2010 with .NET Framework 4.0. 我将Visual Studio 2010与.NET Framework 4.0一起使用。
You could try this: 你可以试试这个:
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);
}
Call it as follows: 称其如下:
query = query.WhereColumnContains(item => item.Omschrijving, search);
You can use a Strategy Pattern. 您可以使用策略模式。 You will have 4 strategies based on the "search" value and with a "bool CanHandle(search)" method, a factory the create a List of strategies, and your program will call a client that simply create a new factory, call a method "BuildQuery(search)" that execute the right strategy found with the CanHandle method, and return a query value.
你将有4个基于“搜索”值的策略和一个“bool CanHandle(搜索)”方法,一个工厂创建一个策略列表,你的程序将调用一个只创建一个新工厂的客户端,调用一个方法“BuildQuery(搜索)”执行使用CanHandle方法找到的正确策略,并返回查询值。
http://en.wikipedia.org/wiki/Strategy_pattern http://en.wikipedia.org/wiki/Strategy_pattern
You could use dynamically built expressions. 您可以使用动态构建的表达式。
Here is a sample code to implement StartWith on multiple columns (may not compile, i'm typing it directly in stackoverflow)- just add support to other methods... 下面是在多列上实现StartWith的示例代码(可能无法编译,我直接在stackoverflow中键入它) - 只需添加对其他方法的支持...
This code works on all linq-to-sql queries, assuming "columnsToSearch" is always refering to string properties. 此代码适用于所有linq-to-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);
In a nutshell, if you had a query myRepository.Where(t=>t.Mycondition)
this code will generate a new query like myRepository.Where(t=>t.Mycondition).Where(t=>t.Field1.StartsWith("a")||t.Field2.StartWith("a"))
(depending on which columns you gave to it of course) 简而言之,如果你有一个查询
myRepository.Where(t=>t.Mycondition)
这段代码将生成一个新的查询,如myRepository.Where(t=>t.Mycondition).Where(t=>t.Field1.StartsWith("a")||t.Field2.StartWith("a"))
(取决于你给它的列当然)
Then, all you have to do is to cast back "myQueryFiltered" to IEnumerable or IQueryable in order to execute it an get filtered results :) 然后,您所要做的就是将“myQueryFiltered”强制转换为IEnumerable或IQueryable,以便执行get过滤结果:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.