我有一个“员工评估”表的列表,该表具有TotalResult
字段,此字段中的值介于1到10之间。另一个表“结果细分”具有以下列:
Id int, Max double, Min double, Desc string
假设我有此数据用于员工评估:
EmpId EmpName TotalResult
--- ------- -----------
1 Jaims 1.5
2 Johny 8.3
3 Moon 5.6
4 Michle 7
5 Mariam 9
6 Kamel 4
结果细分值
Id Max Min Desc
--- --- --- -----
1 3 1 ~ 30%
2 4 3 40%
3 5 4 50%
4 6 5 60%
5 7 6 70%
6 10 7 ~ 80%
现在,用户具有“费率细分”表的多选列表
如果用户选择70%和40%,则查询应显示以下员工评估:
EmpId EmpName TotalResult
----- ------- -----------
3 Moon 5.6
6 Kamel 4
4 Michle 7
我写了这段代码
if (rateSegIds != null)
{
var rateSegs = _repositoryRateSeg.Query(x => rateSegId.Contains(x.Id)).ToList();
if (rateSeg.Any())
{
foreach (var segmentation in rateSeg)
{
query = query.Where(x => x.TotalResult > segmentation.Min && x.TotalResult <= segmentation.Max);
}
}
}
rateSegIds
是保存用户选择的整数列表rateSegs
根据ID列表包含RateSegmataions表中的记录EmployeeAppraisal
表此代码仅在用户从列表中选择一个值时才有效,如果他/她选择多个值,则查询将不返回任何内容。
因为它的作用类似于“ And”,所以它的作用应类似于“ OR”,但我不知道该怎么写。
答案 0 :(得分:0)
这是让我烦恼了一段时间的问题,这个问题促使我稍微深究一下。 .Where()
将使用AndAlso操作附加条件,但正如您指出的那样。为了使EF和Linq更动态地支持OrElse条件,您需要将条件树或条件一起重建一点。恭敬user743382在Exception using OrElse and AndAlso expression methods
您将需要几个类,以使表达式访问者可以将要与多个表达式组合在一起的参数。像这样:
private Expression<Func<EmployeeAppraisal, bool>> buildFilterExpression(IEnumerable<Segment> segments)
{
Expression<Func<EmployeeAppraisal, bool>> exp = c => false;
foreach (var segment in segments)
{
Expression<Func<EmployeeAppraisal, bool>> filter = x => x.TotalResult >= segment.Min && x.TotalResult <= segment.Max;
exp = Expression.Lambda<Func<EmployeeAppraisal, bool>>(Expression.OrElse(exp.Body,
new ExpressionParameterReplacer(filter.Parameters, exp.Parameters).Visit(filter.Body)), exp.Parameters);
}
return exp;
}
private class ExpressionParameterReplacer : ExpressionVisitor
{
public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
{
ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
ParameterReplacements.Add(fromParameters[i], toParameters[i]);
}
private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements
{
get;
set;
}
protected override Expression VisitParameter(ParameterExpression node)
{
ParameterExpression replacement;
if (ParameterReplacements.TryGetValue(node, out replacement))
node = replacement;
return base.VisitParameter(node);
}
}
然后在您的EF Linq表达式中:
var rateSegs = _repositoryRateSeg.Query(x => rateSegId.Contains(x.Id)).ToList();
if (rateSeg.Any())
query = query.Where(buildFilterExpression(rateSegs));
ExpressionParameterReplacer和支持类可对不同的表达式主体进行“或”运算,并确保它们与相同的表达式参数相关联,以便Linq可以将它们正确地评估为单个表达式。
答案 1 :(得分:0)
交叉连接可以是以下一种解决方案:
var rateSegIds = new int[] {2, 5}; //40% and 70%
var result = from emp in EmployeeAppraisals
from segment in Segments.Where(x => rateSegIds.Contains(x.Id))
where emp.Total >= segment.Min && emp.Total <= segment.Max
select emp;