首页 > 解决方案 > .Net 领域的动态查询构建器

问题描述

我正在使用 Realm 数据库在我的设备上本地存储数据。在应用程序中,用户可以查看书籍列表并对其应用过滤器/排序。一本书是一个 Pojo 对象,它具有标题、作者(字符串)、状态(枚举)和发布日期(时间戳)。应用程序的用户可以根据这四个字段过滤书籍,对象上有更多字段,但为简单起见,我目前只使用 4 个。

我正在尝试创建一个动态查询构建器,其中所有选定的过滤器都将应用于查询。

我在文档中看到的是我们可以像这样查询领域

 var allBooks = realm.All<Book>().Where(book =>
        book.Title== "Star wars" ||
        book.Status== "Sold");

我想要的是通过将过滤器列表传递给方法来自己构建查询。我正在考虑使用键/值对创建一个包装器类并分配过滤器的名称和值。然后我可以将这些列表传递给一个方法。我的问题是如何从键/值列表构建查询构建器,其中键是对象字段,如“标题”、“状态”,值是“星球大战”、“已售”。

任何帮助将不胜感激。

标签: c#realm

解决方案


您可以使用 Linq 表达式创建动态谓词:

public static Expression<Func<T, bool>> CreatePredicate<T>(KeyValuePair<string, string>[] filters)
{
    var type = typeof(T);
    var parameter = Expression.Parameter(type, "t");

    if (filters.Length == 0)  // no filtering
        return Expression.Lambda<Func<T, bool>>(Expression.Constant(true), parameter);

    Expression body = Expression.Constant(false);
    foreach (var filter in filters)
    {
        var member = Expression.PropertyOrField(parameter, filter.Key);
        var value = Expression.Constant(filter.Value);
        body = Expression.OrElse(body, Expression.Equal(member, value));
    }

    return Expression.Lambda<Func<T, bool>>(body, parameter);
}

现在如果All<Book>()返回一个IQueryable<Book>使用它:

var predicate = CreatePredicate<Book>(new[]
{
    new KeyValuePair<string, string>("Title", "Star wars"),
    new KeyValuePair<string, string>("Status", "Sold"),
});

var allBooks = realm.All<Book>().Where(predicate);

如果All<Book>()返回IEnumerable<Book>您仍然可以使用它,只需添加调用Compile

var allBooks = realm.All<Book>().Where(predicate.Compile());

推荐阅读