使用 Linq 无需硬编码的多个复选框选择结果
Multiple CheckBox Selection Result using Linq without hardcoding
数据库说明(实际列和table名称不同)
EmployeeeID IsSicked IsRetired IsHoliday
1 false false true
2 true false true
3 true true true
4 false false false
我遇到了什么问题?
我的应用程序中有一个 IsSicked、IsRetired 和 IsHoliday 复选框,允许用户检查多项选择并提交。
系统会根据用户的选择从数据库中return 员工列表。例如,当用户勾选 IsSicked 和 IsRetired 时,系统将从数据库中 return 生病和退休的用户列表。
基于下面的代码,我需要写出 2^3 = 8 种可能性来得到结果。
随着该列扩展到 n 列(不包括 employeeID 列),我将需要编写 2^n if else 语句来获取查询。
如果有 10 列(10 个复选框选择),那么我需要写 2^10 = 1024 if else statement
在我看来,这应该是开发人员面临的一个相当普遍的问题,不幸的是我在网上找不到很好的解决方案
解的期望值
C# 代码的通用组合 and/or LINQ 查询不需要硬编码逻辑如下 if(...) else if (...)
var employee = db.Employee.AsQueryable():
if(model.IsSicked == true)
{
employee.Where(z => z.IsSicked == true)
}
else if(model.IsRetired == true)
{
employee.Where(z => z.IsRetired == true)
}
...
...
else if(model.IsSicked == true && model.IsRetired == true)
{
employee.Where(z => z.IsSick == true || z.IsRetired == true)
}
else if (model.IsSicked == true && model.IsRetired == true && model.IsHoliday == true)
{
employee.Where(z => z.IsSick == true || z.IsRetired == true || z.IsHoliday == true)
}
您可以使用名为 LINQKit 的库并使用其 PredicateBuilder 来创建具有动态 OR 的谓词。
var employee = db.Employee.AsQueryable():
var predicate = PredicateBuilder.False<Employee>();
if (model.IsSicked == true)
predicate = predicate.Or(p => p.IsSick == model.IsSick);
if (model.IsRetired == true)
predicate = predicate.Or(p => p.IsRetired == model.IsRetired);
if (model.IsHoliday == true)
predicate = predicate.Or(p => p.IsHoliday == model.IsHoliday);
var result = employee.AsExpandable().Where(c => predicate.Invoke(c)).ToList()
为什么不使用 enum
和 [Flags]
:
[Flags]
public enum EmployeeStatus
{
None = 0,
Sick = 1,
Retired = 2,
Holiday = 4
}
在您的数据库中,您可以将其存储为整数。
您的模型变得类似于
public class Employee
{
public int Id { get; set; }
public EmployeeStatus Status { get; set }
}
然后 LINQ 查询变得类似于:
employee.Where(z => z.Status == EmployeeStatus.Sick)
由于使用 [Flags]
,您可以对多个状态执行以下操作,例如生病和退休:
employee.Where(z => z.Status == (EmpoyeeStatus.Sick | EmployeeStatus.Retired))
请注意 |
是布尔值 OR,其翻译如下:
EmpoyeeStatus.Sick | EmployeeStatus.Retired
= 1 | 2
= b01 | b10
= b11
= 3
在我们的逻辑中与 "and" 一样有效。
您可以像这样构建 Where 谓词:
var employee = db.Employee.AsQueryable():
if(model.IsSicked == true)
employee = employee.Where(z => z.IsSicked == true)
if(model.IsRetired == true)
employee = employee.Where(z => z.IsRetired == true)
if (model.IsHoliday == true)
employee = employee.Where(z => z.IsHoliday == true)
或者,您可以这样做:
employee.Where(z => (z.IsSicked || !model.IsSicked) &&
(z.IsRetired || !model.IsRetired) &&
(z.IsHoliday || !model.IsHoliday))
数据库说明(实际列和table名称不同)
EmployeeeID IsSicked IsRetired IsHoliday
1 false false true
2 true false true
3 true true true
4 false false false
我遇到了什么问题?
我的应用程序中有一个 IsSicked、IsRetired 和 IsHoliday 复选框,允许用户检查多项选择并提交。
系统会根据用户的选择从数据库中return 员工列表。例如,当用户勾选 IsSicked 和 IsRetired 时,系统将从数据库中 return 生病和退休的用户列表。
基于下面的代码,我需要写出 2^3 = 8 种可能性来得到结果。 随着该列扩展到 n 列(不包括 employeeID 列),我将需要编写 2^n if else 语句来获取查询。 如果有 10 列(10 个复选框选择),那么我需要写 2^10 = 1024 if else statement
在我看来,这应该是开发人员面临的一个相当普遍的问题,不幸的是我在网上找不到很好的解决方案
解的期望值
C# 代码的通用组合 and/or LINQ 查询不需要硬编码逻辑如下 if(...) else if (...)
var employee = db.Employee.AsQueryable():
if(model.IsSicked == true)
{
employee.Where(z => z.IsSicked == true)
}
else if(model.IsRetired == true)
{
employee.Where(z => z.IsRetired == true)
}
...
...
else if(model.IsSicked == true && model.IsRetired == true)
{
employee.Where(z => z.IsSick == true || z.IsRetired == true)
}
else if (model.IsSicked == true && model.IsRetired == true && model.IsHoliday == true)
{
employee.Where(z => z.IsSick == true || z.IsRetired == true || z.IsHoliday == true)
}
您可以使用名为 LINQKit 的库并使用其 PredicateBuilder 来创建具有动态 OR 的谓词。
var employee = db.Employee.AsQueryable():
var predicate = PredicateBuilder.False<Employee>();
if (model.IsSicked == true)
predicate = predicate.Or(p => p.IsSick == model.IsSick);
if (model.IsRetired == true)
predicate = predicate.Or(p => p.IsRetired == model.IsRetired);
if (model.IsHoliday == true)
predicate = predicate.Or(p => p.IsHoliday == model.IsHoliday);
var result = employee.AsExpandable().Where(c => predicate.Invoke(c)).ToList()
为什么不使用 enum
和 [Flags]
:
[Flags]
public enum EmployeeStatus
{
None = 0,
Sick = 1,
Retired = 2,
Holiday = 4
}
在您的数据库中,您可以将其存储为整数。
您的模型变得类似于
public class Employee
{
public int Id { get; set; }
public EmployeeStatus Status { get; set }
}
然后 LINQ 查询变得类似于:
employee.Where(z => z.Status == EmployeeStatus.Sick)
由于使用 [Flags]
,您可以对多个状态执行以下操作,例如生病和退休:
employee.Where(z => z.Status == (EmpoyeeStatus.Sick | EmployeeStatus.Retired))
请注意 |
是布尔值 OR,其翻译如下:
EmpoyeeStatus.Sick | EmployeeStatus.Retired
= 1 | 2
= b01 | b10
= b11
= 3
在我们的逻辑中与 "and" 一样有效。
您可以像这样构建 Where 谓词:
var employee = db.Employee.AsQueryable():
if(model.IsSicked == true)
employee = employee.Where(z => z.IsSicked == true)
if(model.IsRetired == true)
employee = employee.Where(z => z.IsRetired == true)
if (model.IsHoliday == true)
employee = employee.Where(z => z.IsHoliday == true)
或者,您可以这样做:
employee.Where(z => (z.IsSicked || !model.IsSicked) &&
(z.IsRetired || !model.IsRetired) &&
(z.IsHoliday || !model.IsHoliday))