Номер 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));