در بسیاری از پروژههای نرمافزاری، نیاز داریم تا بر اساس ورودیهای کاربر، فیلترهایی را به صورت پویا روی دادهها اعمال کنیم. یکی از چالشهای رایج، ترکیب چند شرط با عملگر OR در کوئریهای LINQ است، بهویژه زمانی که از LINQ to SQL استفاده میکنیم.
مشکل کجاست؟
در LINQ، وقتی چند .()Where پشت سر هم استفاده میکنیم، شرطها به صورت AND ترکیب میشوند. اما اگر بخواهیم چند شرط را با OR ترکیب کنیم، نمیتوانیم به راحتی از .()Or استفاده کنیم، چون <<Expression<Func<T, bool چنین متدی ندارد.
راهحل: استفاده از Expression.OrElse
برای ساخت شرطهای OR، باید از Expression.OrElse استفاده کنیم و پارامترهای مشترک را با دقت جایگزین کنیم. در ادامه، روشی ارائه میشود که لیستی از شرطها را دریافت کرده و آنها را با OR ترکیب میکند:
public static Expression<Func<T, bool>> OrElse<T>(IEnumerable<Expression<Func<T, bool>>> expressions)
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression? body = null;
foreach (var expr in expressions)
{
var visitor = new ReplaceParameterVisitor(expr.Parameters[0], parameter);
var visitedBody = visitor.Visit(expr.Body);
body = body == null ? visitedBody : Expression.OrElse(body, visitedBody);
}
return body != null
? Expression.Lambda<Func<T, bool>>(body, parameter)
: x => false;
}
class ReplaceParameterVisitor : ExpressionVisitor
{
private readonly ParameterExpression _oldParam;
private readonly ParameterExpression _newParam;
public ReplaceParameterVisitor(ParameterExpression oldParam, ParameterExpression newParam)
{
_oldParam = oldParam;
_newParam = newParam;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node == _oldParam ? _newParam : base.VisitParameter(node);
}
}
مثال:
فرض کنید میخواهید لیستی از افراد را فیلتر کنید که یا سنشان بالای ۳۰ باشد، یا نامشان با "ن" شروع شود، یا فعال باشند:
var filters = new List<Expression<Func<Person, bool>>>
{
p => p.Age > 30,
p => p.Name.StartsWith("ن"),
p => p.IsActive
};
var combined = OrElse(filters);
var result = db.People.Where(combined);
این کوئری به صورت زیر در SQL ترجمه میشود:
WHERE Age > 30 OR Name LIKE 'ن%' OR IsActive = 1
🔗 جهت آشنایی و مطالعه بیشتر اینجا و اینجا را میتوانید ببینید.
___________
⁉️ برای بحث و تبادل نظر فنی در مورد این پست، نظرات خود را با ما در قسمت کامنتها به اشتراک بگذارید.
#نگار_قاسمی (لینکدین)
کانال تلگرام:
@SoftwarePhilosophy
________