Динамический построитель запросов для .Net realm - PullRequest
1 голос
/ 26 марта 2019

Я использую базу данных Realm для локального хранения данных на моем устройстве.В приложении пользователь может увидеть список книг и применить к ним фильтры / сортировку.Книга - это объект Pojo, который имеет заголовок, автора (строка), статус (перечисление) и дату публикации (отметка времени).Пользователь приложения может фильтровать книги по этим четырем полям, в объекте больше полей, но для простоты на данный момент я использую только 4.

Я пытаюсь создать динамический построитель запросов, в котором всевыбранные фильтры будут применены к запросу.

То, что я видел в документации, - это то, что мы можем запросить область, подобную этой

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

, что я хочу, это построить запрос на моемсобственные, передав список фильтров в методе.Я думал о создании класса-оболочки с парой ключ / значение и назначении имени фильтра и значения.Тогда я мог бы передать список этих методов.Мой вопрос заключается в том, как построить построитель запросов из списка ключ / значение, где ключом является поле объекта, такое как «Заголовок», «Статус», а значение «Звездные войны», «Продано».

ЛюбойПомощь будет очень признателен.

1 Ответ

2 голосов
/ 26 марта 2019

Вы можете создать динамический предикат с помощью выражений 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());
...