我有一個主要的EF核心查詢,通過IQueryable.Where()附加了一些AND搜索標準。沒有問題。
并且通過Expression<Func<T, bool>> orFilter,有一些OR搜索條件適用于它。
并通過以下方式與OR相連接。orFilter = orFilter.Or(p=>p.Prop == foo)。
最后,它將通過mainQuery.Where(orFilter)作為AND搜索條件應用到主查詢;沒有問題。
但是其中一個OR搜索條件是針對另一個表的,需要連接到另一個表,它回傳IQueryable< T>。我想通過orFilter = orFilter.Or(joinQuery.Expression as Expression<Func<Product, bool>>);將其應用于orFilter,但它沒有作業。
或者有什么相等的方法來實作它?
IQueryable<Product> records = DBContext.Product
.Include(p => p.Item1)
...;
if (filterANDCriteria1.HasValue)
{
records= records.Where(p.xxx == filterANDCriteria1)。
}
Expression<Func<Product, bool>> orFilter= null;
if(filterOrCriteriaP1.HasValue)
{
orFilter= orFilter.Or(p=>p.yyy==filterOrCriteriaP1 ) 。
}
if(filterOrCriteriaP2.HasValue)
{
//加入另一個表,例如類別的偽代碼。
IQueryable<Product> joinQuery =
records.Join(Category.EntityId == Product.Id and Category.EntityType == EntityType.Product and Category.FieldFoo == filterOrCriteriaP2) 。
(product,category)=> product;
//Want to append the query to orFilter here but it not work and return null.
orFilter = orFilter.Or(joinQuery.Expression as Expression<Func<Product, bool>>); //return null
//只對AND查詢有效,以下代碼將回傳符合連接結果和其他過濾器(如filterANDCriteria1)的產品。
// records = joinQuery;
}
if(orFilter!=null)
{
//將整個orFilter作為AND過濾器應用于主查詢。
records = records.Where(orFilter);
}
return records.ToList();
uj5u.com熱心網友回復:
下面是這段代碼,可能對你有幫助。
public static class PredicateBuilder
{
public static IQueryable< T> WhereAny<T>()
this IQueryable<T> source,
params Expression<Func<T, bool>>[] predicates)
{
if (source == null) throw new ArgumentNullException)。
var exp = GetPredicates(predicates);
return source.Where(exp)。
}
private static Expression< Func<T, bool> > GetPredicates<T>(Expression<Func<T, bool> > [] predicates)
{
if (predicates == null) throw new ArgumentNullException)。
if (predicates.Length == 0) return x => false;
if (predicates.Length == 1) return predicates[0] 。
var exp = predicates[0] 。
for (var i = 1; i < predicates.Length; i )
{
exp = exp.OrElse(predicates[i])。
}
return exp;
}
public static Expression< Func<T, bool> > OrElse< TA, T>(this IEnumerable< TA> args, Func<TA, Expression<Func<T, bool>>> expression)。
{
return args.Select(expression).ToList().OrElse()。
}
public static Expression< Func<T, bool> > OrElse<T>(this List< Expression<Func<T, bool>> expressions)。
{
if (expressions.Count <= 0) return null。
var expression = expressions[0] 。
for (var i = 1; i < expressions.Count; i )
{
expression = expression.OrElse(expressions[i])。
}
return expression;
}
public static Expression<Func< T, bool>> OrElse<T>(
this Expression<Func<T, bool> > expr1,
Expression<Func<T, bool>> expr2)。
{
var parameter = Expression.Parameter(typeof(T), expr1.Parameters[0].Name) 。
var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter) 。
var left = leftVisitor.Visit(expr1.Body)。
var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter)。
var right = rightVisitor.Visit(expr2.Body)。
return Expression.Lambda<Func<T, bool> >(
Expression.OrElse(left, right), parameter)。
}
public static Expression< Func< T, bool>> AndAlso<T>()
this Expression<Func<T, bool> > expr1,
Expression<Func<T, bool>> expr2)。
{
var parameter = Expression.Parameter(typeof(T), expr1.Parameters[0].Name) 。
var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter) 。
var left = leftVisitor.Visit(expr1.Body)。
var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter)。
var right = rightVisitor.Visit(expr2.Body)。
return Expression.Lambda<Func<T, bool> >(
Expression.AndAlso(left, right), parameter)。
}
private class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue。
_newValue = newValue。
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue。
return base.Visit(node)。
}
}
}
使用示范:
var users = ctx.Users.WhereAny(ids. Select(id => (Expression<Func<T, bool>>)(g => g.Id == id)).ToArray())。
而且你可以有新的擴展方法,那么它使用起來就更容易了。
public static IQueryable< User> WhereAnyId()
this IQueryable< User> source,
params Guid[] ids)。
{
if (source == null) throw new ArgumentNullException(nameof(source))。
return source.WhereAny(ids.Select(id => (Expression<Func<User, bool> >)(g => g.Id ==id)).ToArray())。
}
var users = ctx.Users.WhereAnyId(ids).ToList()。
uj5u.com熱心網友回復:
最后我得到了一個解決方法。 由于是一對一的映射,我在產品表中添加了一個新的列,例如,名為CategoryId。當創建產品類別時,將CategoryId填回產品表中。
并且包括型別為Category的屬性,并添加資料注釋[ForeignKey]以指向CategoryId。 所以可以使用.Include(p=>p.Category)和使用orFilter = orFilter.Or(p=>p.Category.xxx == filterOrCriteriaP2.Value);
對于其他物體,例如訂單,它不會受到影響。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/309890.html
標籤:
