基于请求api的C#过滤器

时间:2020-08-15 09:03:21

标签: c# .net asp.net-web-api asp.net-core-webapi

我正在尝试过滤应用程序中显示的帖子。一切都按预期进行,但我有一个小问题。用户可以选择他所遵循的教育和专业。如何根据获得的数组进行过滤?我尝试过类似的方法,但是感觉很丑。如果在我的Filter类中设置更多数组,例如Language []。它将变得更加混乱。我可以做些简单的事吗?

public class Filter
{
    public string[] Education { get; set; }

    public string[] Profession { get; set; }
    public int PageIndex { get; set; }

}

示例请求: An example

public PaginatedResults<Post> FilterPosts(Filter filter)
{

// Both Education and Profession arrays are empty, we just return all the posts
    if(filter.Profession.Any(prof => prof == null) && filter.Education.Any(study => study == null)) {
        var posts1 = _dbContext.Posts.AsEnumerable();
        return _searchService.Pagination<Post>(posts1, filter.PageIndex);
    }
    else 
    {
        // Can this be simplified? Sometimes the Education array is empty and sometimes Profession array. User can choose
        IEnumerable<Post> posts = null;
        if(filter.Profession.Any(prof => prof == null)) 
        {
            posts = _dbContext.Posts.Where(post => filter.Education.Contains(post.Education)).AsEnumerable();
        }
        else if(filter.Education.Any(study => study == null)) 
        {
            posts = _dbContext.Posts.Where(post => filter.Profession.Contains(post.Profession)).AsEnumerable();
        }
        else 
        {
            posts = _dbContext.Posts.Where(post => filter.Profession.Contains(post.Profession) && filter.Education.Contains(post.Education)).AsEnumerable();
        }
        return _searchService.Pagination<Post>(posts, filter.PageIndex);
    }
}

1 个答案:

答案 0 :(得分:1)

可能有很多方法可以解决此问题。假设您希望保留您的方法(我认为这是完全有效的),则可以尝试以下步骤:

杠杆IQueryable

假设您使用实体框架,我相信_dbContext.Posts已经实现了IQueryable。由于LINQ不会立即执行,因此我们可以在枚举集合之前按顺序构建过滤条件:

posts = _dbContext.Posts.Where(post => filter.Education.Contains(post.Education) && filter.Education.Contains(post.Profession)).AsEnumerable();

// since you are implementing `AND` semantics for your filters, is easy to break down into series of `.Where()` calls
posts = _dbContext.Posts.Where(post => filter.Education.Contains(post.Education))
                        .Where(post => filter.Education.Contains(post.Profession))
                        .AsEnumerable(); // this should filter Posts by Education AND Profession as well as represent the result as IEnumerable. Should be functionally identical to the first statement

反转布尔条件并检查过滤器是否具有

这将使您仅在需要时添加.Where过滤器:

if (filter.Profession.Any()) // if Profession has elements
{
    posts = posts.Where(post => filter.Profession.Contains(post.Profession)); // apply respective filter to posts, you may want to ensure you only compare against meaningful search terms by appplying `.Where(i => !string.IsNullOrWhiteSpace(i))` to it
}
if (filter.Education.Any()) // if Education has elements
{
    posts = posts.Where(post => filter.Education.Contains(post.Education)).AsEnumerable(); // apply respective filter to posts          
}

然后,将它们放在一起

public PaginatedResults<Post> FilterPosts(Filter filter)
{
    IQueryable<Post> posts = _dbContext.Posts;
    if (filter.Profession.Any()) posts = posts.Where(post => filter.Profession.Contains(post.Profession));

    if (filter.Education.Any()) posts = posts.Where(post => filter.Education.Contains(post.Education));

    return _searchService.Pagination<Post>(posts.AsEnumerable(), filter.PageIndex); 
}