Reputation: 718
I am trying to query database using EF and LINQ. I have multiple queries to filter data based on user permissions with in the application.
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.
};
This is the example of a base query. To this I need to add one more where clauses if user belongs to a specific role and a new table if user belongs to some other role. I was able to do this with five different queries with if...else condition checks. But a new requirement brings more conditions and more tables and more where clauses to be added which makes the code so repetitive that turns out to be a nightmare for maintenance .
I tried PredicateBuilder but I am not sure how can I apply PredicateBuilder with multiple entities and outer join's.
I found about Dynamic LINQ Library from ScottGu's block but I am not sure if it has a .Net 4.5 version and is helpful in this case.
Is there a way that I can construct the query dynamically so that I don't need to change every query when there is a small change in the requirement.
Upvotes: 0
Views: 147
Reputation: 21492
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);
Although, I'd recommend reusing the EF objects, and making sure you have navigation properties set up correctly. From your code, it looks like you aren't using them at all -- which leads you to the mess you have. You really should just have something like these extension methods:
public static IQueryable<EmployeeDetails> IsActive(this IQueryable<EmployeeDetails> eb) {
return eb.Where(p=>p.IsActive == true || p.SomeStatus == null);
}
Then you can access your data like:
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);
}
Upvotes: 2