Search code examples
c#asp.net-coregenericspredicate

How to convert my predicate to a generic predicate in C#?


I have a predicate code that works perfectly but I want to reduce my code and convert it to generic and use it in my repository

public abstract class RequestParameters
{
    const int maxPageSize = 5;
    public int PageNumber { get; set; } = 1;

    private int _pageSize = 10;
    public int PageSize
    {
        get
        {
            return _pageSize;
        }
        set
        {
            _pageSize = (value > maxPageSize) ? maxPageSize : value;
        }
    }
    public string OrderBy { get; set; }
    public string Fields { get; set; }
}

and this is my EmployeeSearchModel

public class EmployeeSearchModel : RequestParameters
{
    public EmployeeSearchModel()
    {
    
        OrderBy = "name";
    }       

    public string Name { get; set; }
    public int Age { get; set; }
    public string Position { get; set; }

    public Expression<System.Func<Employee, bool>> Go()
    {
        var predicate = PredicateBuilder.True<Employee>();

        if (!string.IsNullOrEmpty(Name))
        {
            predicate = predicate.And(i => i.Name.ToLower().Contains(Name.ToLower()));
        }
        if (!string.IsNullOrEmpty(Position))
        {
            predicate = predicate.And(i => i.Position.ToLower().Contains(Position.ToLower()));
        }
        return predicate;
    }
}

and this is my Repository

public async Task<PagedList<Employee>> GetEmployeesAsyncExp(EmployeeSearchModel employeeParameters)
    {
        Expression f = employeeParameters.Go();

        var employees = await FindByCondition(employeeParameters.Go())
        .OrderBy(e => e.Name)           
        .ToListAsync()....

....

and now I want to change it to generic somethings like this:

public class EmployeeSearchModel<T> : RequestParameters ...

Solution

  • Well, there's no real question here and a lot of missing information and also misinformation. I guess you'll want to exchange the "Employee" class to also filter other classes with your SearchModel part. Therefore "EmployeeSearchModel" is wrong, as it still contains the Employee.

    On the other hand, your method is using some Employee specific parts like Name or Age and unless your other classes also contain Age and Name this can't be used as method generic.

    The best part you can do to reuse your SearchModel is to change it to an abstract class and let EmployeeSearchModel inherit that:

    public abstract class SearchModel<T> : RequestParameters
    {
        public abstract Expression<System.Func<T, bool>> Go();
    }
    
    public class EmployeeSearchModel : SearchModel<Employee>
    {
        public EmployeeSearchModel()
        {
    
            OrderBy = "name";
        }
    
        public string Name     { get; set; }
        public int    Age      { get; set; }
        public string Position { get; set; }
    
        public override Expression<Func<Employee, bool>> Go()
        {
            var predicate = PredicateBuilder.True<Employee>();
    
            if (!string.IsNullOrEmpty(Name))
            {
                predicate = predicate.And(i => i.Name.ToLower().Contains(Name.ToLower()));
            }
            if (!string.IsNullOrEmpty(Position))
            {
                predicate = predicate.And(i => i.Position.ToLower().Contains(Position.ToLower()));
            }
            return predicate;
        }
    }
    

    You can then use it to also search with other classes like a Company:

    public class CompanySearchModel : SearchModel<Company>
    {
        public string Department {get; set;}
    
        public override Expression<Func<Company, bool>> Go()
        {
            var predicate = PredicateBuilder.True<Company>();
    
            if (!string.IsNullOrEmpty(Department))
            {
                predicate = predicate.And(x => x.Department.ToLower().Contains(Department.ToLower()));
            }
        }
    }