Номер Android: заказ Не работает

Я использую новую комнату Android ORM. И я столкнулся со следующей проблемой: запросы, которые используют ORDER BY с аргументами, не работают.

Если я хочу использовать поле, заполненное параметром для ORDER BY, оно не работает. Он просто ничего не разбирает.

@Query("SELECT * FROM User ORDER BY :orderBY ASC")
List<User> sortedFind(String orderBY);

Но, когда я помещаю столбец ORDER BY непосредственно в запрос для сортировки результатов, он работает так, как ожидалось.

@Query("SELECT * FROM User ORDER BY name ASC")
List<User> sortedFind();

Это ошибка в Android Room, или я делаю что-то неправильно?

Ответ 1

Что происходит

Единственными значениями, которые вы можете передать в качестве параметров для методов @Dao являются значения, а не строки запроса. Причиной этого (я верю) является предотвращение проблем SQL-инъекций.

Почему это так

Например, запрос SELECT * emails WHERE uid =? затем установите значение как "1 OR WHERE isAdmin = true". Это позволит людям запускать собственные запросы на основе вашей базы данных и делать то, что они хотят.

Мое решение

Я столкнулся с этой проблемой. Вот ссылка на мое решение.

Мое решение состоит из двух частей. Первый DynamicQueryservice который генерирует строку запроса и массив значений на основе ввода, затем запускает необработанный запрос и возвращает Cursor. Во-вторых, Cursor2POJO mapper, поэтому мне не нужно много раз Cursor2POJO отображения курсоров для классов, а также не вводить потенциальные проблемы обслуживания. Я просто добавляю аннотации к моим классам (которые соответствуют именам столбцов комнаты), а lib обрабатывает остальные.

Я отделил свой Cursor mapper в свою библиотеку в вашу пользу, не стесняйтесь использовать ее (просто сделал это так, если readme не ясен, или есть ошибки, попавшие мне в комментарии).

PS Моя библиотека не может использовать Room @ColumnInfo для получения имен столбцов, поскольку в настоящее время аннотация установлена как RetentionPolicy.CLASS, поэтому доступ к ней невозможен. (добавлен в отслеживание проблем Google https://issuetracker.google.com/issues/63720940)

Ответ 2

Проблема в том, что вы хотите передать часть инструкции SQL, но Room рассматривает ее как параметр запроса.

Если вы хотите, вы можете попробовать использовать Kripton Persistence Library, библиотеку с открытым исходным кодом, которая поддерживает SQLite для платформы Android и поддерживает ситуации, о которых вы говорили.

Kripton также работает с шаблоном DAO, поэтому концепция довольно схожа. Просто напишите пример, который соответствует вашим потребностям:

Для класса модели:

@BindType
public class User {
    public long id;
    public String name;
    public String username;
    public String email;
    public Address address;
    public String phone;
    public String website;
    public Company company;
}

определение DAO:

@BindDao(User.class)
public interface UserDao {
    @BindSqlInsert
    void insert(User bean);

   @BindSqlSelect
   List<User> sortedFind(@BindSqlDynamicOrderBy String orderBy);
}

и определение источника данных:

@BindDataSource(daoSet={UserDao.class}, fileName = "kripton.quickstart.db", generateAsyncTask = true)
public interface QuickStartDataSource {
}

Криптон будет генерировать во время компиляции, все коды должны работать с базой данных. Поэтому для выполнения вашей задачи с Kripton вам нужно написать код, похожий на:

BindQuickStartDataSource ds = BindQuickStartDataSource.instance();
// execute operation in a transaction
ds.execute(new BindQuickStartDataSource.SimpleTransaction() {
  @Override
  public boolean onExecute(BindQuickStartDaoFactory daoFactory) throws Throwable 
  {
    UserDaoImpl dao = daoFactory.getUserDao();
    dao.sortedFind("name asc");
    return true;
  }
});

В logcat, когда выполняется код выше, вы увидите сгенерированный журнал:

database OPEN READ_AND_WRITE_OPENED (connections: 1)
SELECT id, name, username, email, address, phone, website, company FROM user ORDER BY name asc
Rows found: 0
database CLOSED (READ_AND_WRITE_OPENED) (connections: 0)

Очевидно, что Kripton поддерживает статический порядок и многие другие функции (я начал развивать его в 2015 году).

Для получения дополнительной информации о библиотеке сохранения Криптона:

Ответ 3

вы можете упорядочивать данные только в порядке возрастания по имени любого столбца. Программно вы не можете передать какое-либо значение методам Dao

Ответ 4

Вы должны использовать аннотацию @RawQuery и класс SupportSQLiteQuery для выполнения запроса

В Дао:

 @RawQuery
 List<Objects> runtimeQuery(SupportSQLiteQuery sortQuery);

Чтобы получить данные:

String query ="SELECT * FROM User ORDER BY " + targetField + " ASC";
List<Objects> users = appDatabase.daoUser().runtimeQuery(new SimpleSQLiteQuery(query));