mil*_*7en 6 c# sql linq asp.net iqueryable
我正在尝试对某个IQueryable对象进行关键字搜索,但有没有办法在没有先将其转换为列表的情况下执行此操作?
我的代码:
var customers = Customer.IQueryableAll(); // Method returns IQueryable containing all customers.
var customerHolder = new List<Customer>();
foreach(var k in keywords) //keywords = List<string>
{
customerHolder.AddRange(customers.Where(x=>x.FirstName.Contains(k) || x.LastName.Contains(k) || x.CompanyName.Contains(k)).ToList())
}
return customerHolder.Distinct();
Run Code Online (Sandbox Code Playgroud)
如果我想一次显示所有结果,这是有效的,但问题出现在我想要进行分页的地方.在分页之前,该函数仍然会从数据库中获取所有条目,因此它对大型表的效率非常低.(即customerHolder.Skip(5).Take(5);)
有没有办法将foreach搜索部分集成到查询本身?
即.
customers.Where( x => x.Name.Contains(anythingInKeyWords));
Run Code Online (Sandbox Code Playgroud)
编辑:为了进一步澄清,我确实想要保持上面的OR,所以使用多个where子句进行过滤和重新过滤将不起作用.IE浏览器.Bill Job/Bill Gates>搜索Bill Gates应该返回两个条目,因为比尔匹配.
您需要为每个实体的每个关键字构建一个OR表示过滤器表达式结果的查询,这在不使用动态LINQ的情况下不太实用.这是一个扩展方法,可以为您做到这一点:
public static class ExtensionMethods
{
public static IQueryable<TEntity> TestPerKey<TEntity, TKey>(
this IQueryable<TEntity> query,
IEnumerable<TKey> keys,
Expression<Func<TEntity, TKey, bool>> testExpression )
{
// create expression parameter
var arg = Expression.Parameter( typeof( TEntity ), "entity" );
// expression body var
Expression expBody = null;
// for each key, invoke testExpression, logically OR results
foreach( var key in keys )
{
// constant expression for key
var keyExp = Expression.Constant( key );
// testExpression.Invoke expression
var invokeExp = Expression.Invoke( testExpression, arg, keyExp );
if( null == expBody )
{
// first expression
expBody = invokeExp;
}
else
{
// logically OR previous expression with new expression
expBody = Expression.OrElse( expBody, invokeExp );
}
}
// execute Where method w/ created filter expression
return query.Where( ( Expression<Func<TEntity, bool>> )Expression.Lambda( expBody, arg ) );
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
class TestEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CompanyName { get; set; }
}
static void Main()
{
var testCollection = new TestEntity[]{
new TestEntity(){
Id = 0,
FirstName = "abc",
LastName = "def",
CompanyName = "ghi"
},
new TestEntity(){
Id = 1,
FirstName = "def",
LastName = "ghi",
CompanyName = "jkl"
},
new TestEntity(){
Id = 2,
FirstName = "ghi",
LastName = "jkl",
CompanyName = "mno"
},
new TestEntity(){
Id = 3,
FirstName = "bcd",
LastName = "efg",
CompanyName = "hij"
},
};
var keywords = new[]{
"abc",
"jkl"
};
var query = testCollection.AsQueryable()
.TestPerKey(
keywords,
( t, k ) =>
t.FirstName.Contains( k ) ||
t.LastName.Contains( k ) ||
t.CompanyName.Contains( k ) );
foreach( var result in query )
{
Console.WriteLine( result.Id );
}
}
Run Code Online (Sandbox Code Playgroud)
更新 - 尝试以下扩展方法.它更具体,但应与EF一起使用:
public static IQueryable<TestEntity> TestPerKey(
this IQueryable<TestEntity> query,
IEnumerable<string> keys )
{
MethodInfo containsMethodInfo = typeof( string ).GetMethod( "Contains" );
// create expression parameter
var arg = Expression.Parameter( typeof( TestEntity ), "entity" );
// expression body var
Expression expBody = null;
// for each key, invoke testExpression, logically OR results
foreach( var key in keys )
{
var expression = Expression.OrElse(
Expression.OrElse(
Expression.Call( Expression.Property( arg, "FirstName" ), containsMethodInfo, Expression.Constant( key ) ),
Expression.Call( Expression.Property( arg, "LastName" ), containsMethodInfo, Expression.Constant( key ) ) )
, Expression.Call( Expression.Property( arg, "CompanyName" ), containsMethodInfo, Expression.Constant( key ) ) );
if( null == expBody )
{
// first expression
expBody = expression;
}
else
{
// logically OR previous expression with new expression
expBody = Expression.OrElse( expBody, expression );
}
}
// execute Where method w/ created filter expression
return query.Where( ( Expression<Func<TestEntity, bool>> )Expression.Lambda( expBody, arg ) );
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8462 次 |
| 最近记录: |