动态 LINQ 语句

Dynamic LINQ statement

我正在尝试使用 EF 和 LINQ 查询数据库。我有多个查询来根据应用程序中的用户权限过滤数据。

from p in db.EmployeeDetails
join i in db.EmployeeDept on p.DeptId equals i.DeptId into inst
from i in inst.DefaultIfEmpty()
join s in db.Employee on p.EmpId equals s.EmpId into manager
from s in manager.DefaultIfEmpty()
join e in db.EmpStatus on p.EnrollmentStatusID equals e.StatusID into estatus
from e in estatus.DefaultIfEmpty()
where p.SomeId== id && (p.IsActive == true || p.SomeStatus == null)
select new EmployeeBase
{
  //select list common to all queries. 
};

这是基本查询的示例。为此,如果用户属于特定角色,我需要再添加一个 where 子句,如果用户属于其他角色,我需要添加一个新的 table。我能够通过 if...else 条件检查的五个不同查询来做到这一点。但是新的需求带来了更多的条件和更多的 tables 以及更多的 where 子句,这使得代码如此重复以至于成为维护的噩梦。

我尝试了 PredicateBuilder,但我不确定如何将 PredicateBuilder 应用于多个实体和外连接。

我从 ScottGu 的区块中找到了动态 LINQ 库,但我不确定它是否有 .Net 4.5 版本并且在这种情况下是否有用。

有没有一种方法可以动态构建查询,这样我就不需要在需求发生微小变化时更改每个查询。

public IQueryable<EmployeeBase> Employees() {
    return (

    from p in db.EmployeeDetails
    join i in db.EmployeeDept on p.DeptId equals i.DeptId into inst
    from i in inst.DefaultIfEmpty()
    join s in db.Employee on p.EmpId equals s.EmpId into manager
    from s in manager.DefaultIfEmpty()
    join e in db.EmpStatus on p.EnrollmentStatusID equals e.StatusID into estatus
    from e in estatus.DefaultIfEmpty()
    where p.SomeId== id && (p.IsActive == true || p.SomeStatus == null)
    select new EmployeeBase
    {
      //select list common to all queries. 
    });
}

...

var awesomeEmployee=Employees().Single(x=>x.name=="Me");
var listToFire=Employees().OrderByDescending(x=>x.Salary).Take(3);
var listToPromote=Employees().OrderByDescending(x=>x.Performance).Take(1);

不过,我建议重新使用 EF 对象,并确保您正确设置了导航属性。从您的代码来看,您似乎根本没有使用它们——这会导致您陷入混乱。你真的应该有像这些扩展方法这样的东西:

public static IQueryable<EmployeeDetails> IsActive(this IQueryable<EmployeeDetails> eb) {
    return eb.Where(p=>p.IsActive == true || p.SomeStatus == null);
}

然后您可以像这样访问您的数据:

var employee=db.EmployeeDetails
  .IsActive()
  .Include(x=>x.Manager);

foreach(var e in employee) { 
  Console.Writeline("{0}'s manager is {1}",
    e.name,
    e.Manager.name);
}