Linq Expression управляет приоритетом между AndAlso и OrElse
У меня есть динамическая система фильтрации на моем уровне данных, чтобы создать выражение для получения данных.
У меня есть объект запроса, который содержит мою модель фильтрации, а именно:
public class BookingPagerQuery : PagerQuery
{
public bool? IsAssignedToPlanningSlot { get; set; }
public IEnumerable<Guid> PlanningSlotIds { get; set; }
public bool MainInterventionOnly { get; set; }
public bool MainOperatorOnly { get; set; }
}
и внутри методов получения я выполняю процесс фильтрации:
// For all, not deleted and only current establissment
Expression<Func<BookingOperator, bool>> where = a => !a.Deleted && a.EstablishmentId == establishmentId;
// filtering by role
if (userIdentity.Roles.HasAnyFlag(Roles.Admin))
{
// Admin : no filter
}
else if (userIdentity.Roles.HasAnyFlag(BookingRoles.ProcessSentBookings))
{
// booking process granted = no draft from others but his draft
where = where.Combine(c => !new List<BookingState> { BookingState.Draft }.Contains(c.BookingState));
where = where.CombineOrElse(c => c.CreatedBy == userIdentity.Id);
}
else if (userIdentity.Roles.HasAnyFlag(Roles.Secretary))
{
// 1. All self created
// 2. All from his office or service
// 3. with or without operator
Secretary secretary = Context.Secretaries.First(x => x.Id == userIdentity.Id);
// 1. Tous ceux créé par elles même
where = where.Combine(a => a.CreatedBy == userIdentity.Id);
// 2. pour son office ou partnerEst.
if (secretary.OfficeId != null)
{
// Les chirurgiens de son office
IEnumerable<Guid> privateSurgeons = Context.PrivateSurgeons.Where(x => x.OfficeId == secretary.OfficeId).Select(x => x.Id);
where = where.CombineOrElse(x => x.OperatorId.HasValue && privateSurgeons.Contains(x.OperatorId.Value));
}
if (secretary.ServiceId != null)
{
// Les chirurgiens de son service
IEnumerable<Guid> serviceMembers = Context.ServiceMembers.Where(x => x.ServiceId == secretary.ServiceId).Select(x => x.Id);
where = where.CombineOrElse(x => x.OperatorId.HasValue && serviceMembers.Contains(x.OperatorId.Value));
}
}
else if (userIdentity.Roles.HasAnyFlag(Roles.Surgeon))
{
// All self created
where = where.Combine(a => a.CreatedBy == userIdentity.Id);
// All given by the secretary
where = where.CombineOrElse(a => a.OperatorId == userIdentity.Id);
}
if (query.MainInterventionOnly)
{
where = where.Combine(a => a.IsMainIntervention == true);
}
if (query.MainOperatorOnly)
{
where = where.Combine(x => !x.OperatorType.HasValue || x.OperatorType == OperatorType.Operator1);
}
Вот код Combine и CombineOrElse:
public static Expression<Func<T, bool>> Combine<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
ParameterExpression param = Expression.Parameter(typeof(T), "param");
Expression newFirst = new ReplaceVisitor(first.Parameters.First(), param).Visit(first.Body);
Expression newSecond = new ReplaceVisitor(second.Parameters.First(), param).Visit(second.Body);
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(newFirst, newSecond), param);
}
public static Expression<Func<T, bool>> CombineOrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
ParameterExpression param = Expression.Parameter(typeof(T), "param");
Expression newFirst = new ReplaceVisitor(first.Parameters.First(), param).Visit(first.Body);
Expression newSecond = new ReplaceVisitor(second.Parameters.First(), param).Visit(second.Body);
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(newFirst, newSecond), param);
}
Я могу переписать код, чтобы удалить все CombineElse
и включить это в Combine
, но система будет расти, и фильтр будет более гранулированным, поэтому мне нужно создать Expression как CombineIncludeOrElse:
Comine: A && B
CombineOrElse: A || В
CombineIncludeOrElse: A && (B || C)
Я тоже переименую Combine и CombineOrElse, AndAlso и OrElse
Итак, как в выражении я могу получить B без A и ввести OrElse на C?