简体   繁体   中英

How to dynamically query IQueryable array by each property using reflection?

I have search method with gets as parameter some DTO and make where filtering dynamically by DTO properties. The problem I get when using reflection is that I should explicitly cast to a property type that I am using. Is there a way to make it dynamic too so that the method that that make filtering can work without knowing type of a property. I am using Dynamic Ling Library.

CODE:

 public async Task<ServiceResponceWithData<List<SearchResponseDTO>>> SearchAsync(SearchDTO model)
    {
        var users = from user in _userManeger.Users
                    join ur in _context.UserRoles
                           on user.Id equals ur.UserId
                    select new SearchResponseDTO
                    {
                        UserName = user.UserName,
                        Email = user.Email,
                        PhoneNumber = user.PhoneNumber,
                        FirstName = user.FirstName,
                        LastName = user.LastName,
                        Roles = _roleManager.Roles
                                .Where(c => c.Id == ur.RoleId)
                                .Select(c => c.Name)
                                .ToList()
                    };

        var startResult = users;

        var props = typeof(SearchDTO).GetProperties();
        foreach (var prop in props)
        {
            if(prop.Name != "Role")
            {
                users = FilterWithWhereByStringTypeProperty(users, prop, model);
            }
            else
            {
                if (model.Role != null)
                {
                    var results = users.Where(c => c.Roles.Any(r => r == model.Role));
                    users = results.Any() ? results : users;
                }
            }
        }

        var endResultList =  startResult == users ? new List<SearchResponseDTO>() :await  users.ToListAsync();

        return new ServiceResponceWithData<List<SearchResponseDTO>>() { Data = endResultList, Success = true };
    }

    private IQueryable<SearchResponseDTO> FilterWithWhereByStringTypeProperty(IQueryable<SearchResponseDTO> collection,
                                                PropertyInfo property,SearchDTO model )
    {
        var propertyName = property.Name;
        var modelPropVal = property.GetValue(model);

        if (modelPropVal == null) return collection;

        string val = (string)modelPropVal;
        string condition = String.Format("{0} == \"{1}\"", propertyName, val);
        var fillteredColl = collection.Where(condition);
        return fillteredColl.Any() ? fillteredColl : collection;
    }
}

You could use System.Linq.Dynamic.Core .

In that case your code could be like ( not tested ):

var users = from user in _userManeger.Users
    join ur in _context.UserRoles on user.Id equals ur.UserId
    select new SearchResponseDTO
    {
        UserName = user.UserName,
        Email = user.Email,
        PhoneNumber = user.PhoneNumber,
        FirstName = user.FirstName,
        LastName = user.LastName,
        Roles = _roleManager.Roles
                .Where(c => c.Id == ur.RoleId)
                .Select(c => c.Name)
                .ToList()
    };

IQueryable query = users;
    
var props = typeof(SearchDTO).GetProperties();
foreach (var prop in props)
{
    if (prop.Name != "Role")
    {
        query = query.Where($"{prop.Name} == @0", prop.GetValue(model, null));
    }
    else
    {
        if (model.Role != null)
        {
            query = users.Where(c => c.Roles.Any(r => r == model.Role));
        }
    }
}

return query.ToList();

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM