So basically I have to get 4 different List of employees for 4 different roles. List of Roles
is a List of Enum
as below:
public enum Roles {
[Description("Level 1")]
L1,
[Description("Level 2")]
L2,
[Description("Level 3")]
L3,
[Description("Level 4")]
L4
};
L1
can view L1
, L2
, L3
and L4
L2
can view L2
, L3
and L4
L3
can view L3
and L4
. L4
do not have permission to view any of employee. Now below is how I have written query for fetching employees.
if (!Equals(Role, Enum.GetName(typeof(GlobalMethods.Roles), 3)))
{
var _role = (GlobalMethods.Roles)Enum.Parse(typeof(GlobalMethods.Roles), Role,true);
List<EmployeeViewModel> employees = new List<EmployeeViewModel>();
switch (_role)
{
case GlobalMethods.Roles.L1:
employees = context.tblEmployees.Where(x => x.EmpID != homeViewModel.UserViewModel.EmpID).ToList().Select(x => new EmployeeViewModel
{
EmpActive = x.EmpActive,
EmpDOB = x.EmpDOB,
EmpName = x.EmpName
}).ToList();
break;
case GlobalMethods.Roles.L2:
employees= context.tblEmployees.Where(x => x.EmpID != homeViewModel.UserViewModel.EmpID).ToList().Where(x=>x.EmpRole != Enum.GetName(typeof(GlobalMethods.Roles), 0)).Select(x => new EmployeeViewModel
{
EmpActive = x.EmpActive,
EmpDOB = x.EmpDOB,
EmpName = x.EmpName,
}).ToList();
break;
case GlobalMethods.Roles.L3:
employees = context.tblEmployees.Where(x => x.EmpID != homeViewModel.UserViewModel.EmpID).ToList().Where(x.EmpRole != Enum.GetName(typeof(GlobalMethods.Roles), 0) && x.EmpRole != Enum.GetName(typeof(GlobalMethods.Roles), 1)).Select(x => new EmployeeViewModel
{
EmpActive = x.EmpActive,
EmpDOB = x.EmpDOB,
EmpName = x.EmpName,
}).ToList();
break;
default: break;
}
}
So in the above code I have the same LINQ query but only the where
condition differs. Is there any way I can prepare a dynamic where
condition and fetch the list once for all?
This should work. It makes the assumption that each GlobalMethods.Roles can view all roles with a greater int values. That is the case for the roles are rules that you have stated.
if (!Equals(Role, Enum.GetName(typeof(GlobalMethods.Roles), 3)))
{
var _role = (GlobalMethods.Roles)Enum.Parse(typeof(GlobalMethods.Roles), Role, true);
List<EmployeeViewModel> employees = new List<EmployeeViewModel>();
string[] viewableRoles = GetViewableRoles(_role);
employees = context.tblEmployees
.Where(x => x.EmpID != homeViewModel.UserViewModel.EmpID && viewableRoles.Contains(x.EmpRole))
.Select(x => new EmployeeViewModel
{
EmpActive = x.EmpActive,
EmpDOB = x.EmpDOB,
EmpName = x.EmpName
}).ToList();
}
private string[] GetViewableRoles(GlobalMethods.Roles userRole)
{
//Uncomment if L4 can actually view no roles, including itself.
// /if (userRole == GlobalMethods.Roles.L4)
// {
// return new string[0];
// }
IEnumerable<GlobalMethods.Roles> allRoles = Enum.GetValues(typeof(GlobalMethods.Roles)).Cast<GlobalMethods.Roles>();
return (from role in allRoles
where (int)role >= (int)userRole
select role.ToString()).ToArray();
}
This is simplified but you can do something like this:
class Program
{
static void Main(string[] args)
{
var list = new List<Person>
{
new Person{ Name = "John" },
new Person{ Name = "Amy" }
};
Func<Person, bool> pred = null;
Roles role = Roles.RoleA;
switch (role)
{
case Roles.RoleA:
pred = p => p.Name.StartsWith("J");
break;
case Roles.RoleB:
pred = p => p.Name.StartsWith("A") && p.Name.Length >= 3;
break;
default:
break;
}
var result = list.Where(pred);
}
}
class Person
{
public string Name { get; set; }
}
enum Roles
{
RoleA,
RoleB
}
Following is the generic Expression tree extension method, to take care of the following requirement (you certainly need to modify to suit your specific requirements)
T
is the final type of IEnumerable
T1
is the type of column for the filtering in the where clause
Declare ParameterExpression
for a given Type T
outside extension method for reuse, while compiling Expression Tree to Func
, though this can also be done separately in the Extension method
and during Func
generation
ParameterExpression parameterType = Expression.Parameter(typeof(T), "object");
public static class CustomExpression { // Create Initial Expression Tree public static BinaryExpression InitialExpression<T,T1>( ParameterExpression parameterType string columnName, T1 value) { // Optional can be taken outside the Extension method to create a Func<T,bool> //ParameterExpression parameterType = Expression.Parameter(typeof(T), "object"); MemberExpression typeColumn = Expression.Property(parameterType, columnName); ConstantExpression constant = Expression.Constant(value, typeof(T1)); return Expression.NotEqual(typeColumn, constant); } // Create Combined Expression Tree public static BinaryExpression CombinedExpression<T,T1>(this BinaryExpression mainExpression, ParameterExpression parameterType string columnName, T1 value) { // Optional can be taken outside the Extension method to create a Func<T,bool> //ParameterExpression parameterType = Expression.Parameter(typeof(T), "object"); MemberExpression typeColumn = Expression.Property(parameterType, columnName); ConstantExpression constant = Expression.Constant(value, typeof(T1)); return Expression.And(mainExpression,Expression.NotEqual(typeColumn, constant)); } }
Following is the Call Hierarchy in your case:
Declare final binary expression for the Linq
query:
BinaryExpression finalBinaryExpression = null;
switch (_role) { case GlobalMethods.Roles.L1: finalBinaryExpression = CustomExpression.InitialExpression<EmployeeViewModel,int> (parameterType,"EmpID",homeViewModel.UserViewModel.EmpID); break; case GlobalMethods.Roles.L2: finalBinaryExpression = CustomExpression.InitialExpression<EmployeeViewModel,int> (parameterType,"EmpID",homeViewModel.UserViewModel.EmpID) .CombinedExpression<EmployeeViewModel,Roles> (parameterType,"EmpRole",Enum.GetName(typeof(GlobalMethods.Roles), 0)); break; case GlobalMethods.Roles.L3: finalBinaryExpression = CustomExpression.InitialExpression<EmployeeViewModel,int> (parameterType,"EmpID",homeViewModel.UserViewModel.EmpID) .CombinedExpression<EmployeeViewModel,Roles> (parameterType,"EmpRole",Enum.GetName(typeof(GlobalMethods.Roles), 0)) .CombinedExpression<EmployeeViewModel,Roles> (parameterType,"EmpRole",Enum.GetName(typeof(GlobalMethods.Roles), 1)); break; }
Create a genericFunc
by compiling the binary expression as follows
Func<T, bool> filterFunc = Expression.Lambda<Func<T, bool>> (finalBinaryExpression, parameterType).Compile();
Final Result Apply the Func
created above
var finalResult = context.tblEmployees.Where(o => filterFunc(o));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.