web-dev-qa-db-fra.com

Android Room: Commandez en ne travaillant pas

J'utilise la nouvelle salle Android ORM. Et je suis confronté au problème suivant: les requêtes qui utilisent ORDER BY avec des arguments ne fonctionnent pas.

Si je veux utiliser le champ renseigné à partir d'un paramètre pour ORDER BY, cela ne fonctionne pas. Ça ne règle rien.

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

Mais, lorsque je mets la colonne ORDER BY directement dans la requête pour trier les résultats, cela fonctionne comme prévu.

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

Est-ce un bug sur Android Room, ou est-ce que je fais quelque chose de mal?

23
Sirelon

Qu'est-ce qui se passe

Les seules valeurs que vous pouvez transmettre en tant que paramètres aux méthodes @Dao sont des valeurs et non des chaînes de requête. La raison de cela (je crois) est d'empêcher les problèmes d'injection SQL.

Pourquoi c'est le cas

Par exemple, la requête SELECT * emails WHERE uid = ? définit ensuite la valeur sur "1 OR WHERE isAdmin = true". Cela permettrait aux gens d'exécuter leurs propres requêtes personnalisées sur votre base de données et de faire ce qu'ils veulent.

Ma solution

J'ai rencontré ce problème aussi. Voici un lien vers mon solution .

Ma solution a 2 parties. La première DynamicQueryservice qui génère la chaîne de requête et le tableau de valeurs en fonction de l'entrée, puis exécute la requête brute et retourne une Cursor. Deuxièmement, un mappeur Cursor2POJO afin que je n'ai pas à écrire des mappages de curseur à plusieurs reprises pour les classes, ni à présenter des problèmes de maintenance potentiels. J'ajoute simplement des annotations à mes classes (qui correspondent aux noms des colonnes de la pièce) et la bibliothèque se charge du reste.

J'ai séparé mon mappeur de curseurs en son propre bibliothèque pour votre bénéfice, n'hésitez pas à l'utiliser (faites-le simplement si le readme n'est pas clair, ou si des bugs me sont signalés). 

P.S. Ma bibliothèque ne peut pas utiliser Room @ColumnInfo pour obtenir les noms de colonne car l'annotation est actuellement définie comme RetentionPolicy.CLASS et ne peut donc pas être consultée par réflexion. (ajouté à l'outil de suivi des problèmes de Google https://issuetracker.google.com/issues/63720940 )

7
Jack Dalton

vous pouvez uniquement organiser les données dans l'ordre croissant en référence au nom de l'une des colonnes . Par programme, vous ne pouvez transmettre aucune valeur aux méthodes Dao.

0
VIKAS SHARMA

Vous devez utiliser l'annotation @RawQuery et la classe SupportSQLiteQuery pour la requête d'exécution.

À Dao:

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

Pour obtenir des données:

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

Le problème est que vous souhaitez transmettre une partie de l'instruction SQL, mais Room la traite comme un paramètre de requête. 

Si vous le souhaitez, vous pouvez essayer d’utiliser Kripton Persistence Library, une bibliothèque open source gérée par la plate-forme de gestion de SQLite pour Android, et de prendre en charge des situations similaires à celles que vous avez mentionnées.

Kripton fonctionne également avec le motif DAO, donc les concepts sont assez similaires. Juste pour écrire un exemple qui correspond à vos besoins:

Étant donné une classe modèle:

@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;
}

une définition DAO:

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

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

et une définition de source de données:

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

Kripton générera à la compilation tout le code est nécessaire pour travailler avec la base de données. Donc, pour accomplir votre tâche avec Kripton, vous devez écrire un code similaire à:

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;
  }
});

Dans logcat lorsque le code ci-dessus est exécuté, vous verrez le journal généré:

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 supporte évidemment aussi l'ordre statique et beaucoup d'autres fonctionnalités (j'ai commencé à le développer en 2015).

Pour plus d'informations sur Kripton Persistence Library:

0
xcesco