web-dev-qa-db-fra.com

Comment interroger dynamiquement la base de données de la salle lors de l'exécution?

Le problème

Est-il possible de construire une requête au moment de l'exécution?


Cas d'utilisation

@Query("SELECT * FROM playlist " +
        "WHERE playlist_title LIKE '% :playlistTitle %' " +
        "GROUP BY playlist_title " +
        "ORDER BY playlist_title " +
        "LIMIT :limit")
 List<IPlaylist> searchPlaylists(String playlistTitle, int limit);

La partie limit est facultative. C'est-à-dire qu'il devrait pouvoir effectuer la même requête avec ou sans limite.


Un cas d'utilisation plus compliqué

Dans le cas précédent, il est possible de faire deux requêtes statiques avec et sans partie limite et une requête appropriée peut être utilisée à chaque fois. Mais parfois, nous pouvons avoir à faire face à des situations plus complexes telles que la construction d'un filtre.

Dans ce cas, contrairement à l'exemple précédent, le nombre de pièces facultatives sera multiple. Pour un tableau de livres, il peut être nécessaire de filtrer en fonction de la catégorie à laquelle appartient le livre, nom de l'auteur, fourchette de prix, date de publication, etc.

18
Anderson K

D'après mon expérience (courte), utiliser ce n'est pas possible, et ce n'est pas parce qu'il s'agit d'une limitation de salle, mais, comme le dit implicitement @CommonsWare, une limitation de SQLite. Vous avez besoin de deux requêtes et donc de deux méthodes dans votre DAO.

Je voudrais avoir quelque chose comme:

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title " +
    "LIMIT :limit")
List<IPlaylist> searchPlaylists(String playlistTitle, int limit);

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title ")
List<IPlaylist> searchPlaylists(String playlistTitle);

Ensuite, ailleurs, vous faites le contournement:

if (limit.isPresent()) {
   return playlistDao.searchPlaylists(title, limit.get());
} else {
   return playlistDao.searchPlaylists(title);
}

C'est la meilleure option que je puisse penser pour le moment.

15
Juanky Soriano

Au lieu d'écrire plusieurs requêtes, je me réfère à passer la valeur négative à la clause limit. Parce que s'il y a un changement dans la requête, je dois mettre à jour la requête qui est plus sujette aux erreurs.

Document officiel -> Si l'expression LIMIT est évaluée à une valeur négative, le nombre de lignes renvoyées n'est pas supérieur. vous pouvez le trouver ici https://sqlite.org/lang_select.html et lisez la section clause limit.

Donc je ferais quelque chose comme ça,

@Query("SELECT * FROM playlist " +
    "WHERE playlist_title LIKE '% :playlistTitle %' " +
    "GROUP BY playlist_title " +
    "ORDER BY playlist_title " +
    "LIMIT :limit")
List<IPlaylist> searchPlaylists(String playlistTitle, int limit);

et passez négatif lorsque vous ne voulez pas appliquer de filtre.

return playlistDao.searchPlaylists(title, limit.isPresent() ? limit.get() : -1)

Cela fonctionne dans mon cas.

Mis à jour le [21 déc 2018]

Si vous utilisez kotlin, utilisez la valeur par défaut.

@JvmOverloads
@Query("SELECT * FROM playlist " +
        "WHERE playlist_title LIKE '% :playlistTitle %' " +
        "GROUP BY playlist_title " +
        "ORDER BY playlist_title " +
        "LIMIT :limit")
fun searchPlaylists(playlistTitle: String, limit: Int = -1): List<IPlaylist>

@JvmOverloads pour le rendre compatible avec Java. Il génère deux méthodes distinctes pour Java. 

10
Moinkhan

Il n'y a pas de paramètre similaire à Room dans Room, mais il existe une annotation @RawQuery dans laquelle vous pouvez transmettre une requête sous forme de chaîne afin de pouvoir générer votre requête SQL lors de l'exécution. Je pense que cela fonctionnera pour vous. 

Voici l'exemple de la documentation Offical:

@Dao
 interface RawDao {
     @RawQuery
     User getUser(String query);
 }

Et voici comment vous pouvez l'utiliser:

User user = rawDao.getUser("SELECT * FROM User WHERE id = 3 LIMIT 1");

Important: Les méthodes RawQuery doivent renvoyer un type non vide

Important: Ceci est disponible dans la salle 1.1.0-alpha3

6
Mladen Rakonjac

Room prend en charge @RawQuery annotation pour construire des requêtes au moment de l'exécution.


Étape 1: Créer la méthode DAO

Marquez la méthode DAO avec l'annotation @RawQuery au lieu de @RawQuery normal.

@Dao
interface BooksDao{
    @RawQuery
    List<Book> getBooks(SupportSQLiteQuery query);
}


Étape 2: Construire la requête

Room utilise des instructions préparées pour la sécurité et la vérification du temps de compilation. Par conséquent, lors de la construction des requêtes, nous devons stocker la chaîne de requête et les paramètres de liaison séparément.

Dans cet exemple, j'utilise la variable queryString pour la chaîne de requête et args pour les paramètres de liaison.

(Veuillez noter que j'ai utilisé un éditeur de texte pour écrire du code. Par conséquent, il peut y avoir des erreurs de frappe ou de syntaxe. Si vous trouvez quelque chose, merci de me le signaler dans les commentaires ou de modifier le message.)

// Query string
String queryString = new String();

// List of bind parameters
List<Object> args = new ArrayList();

boolean containsCondition = false;

// Beginning of query string
queryString += "SELECT * FROM BOOKS";

// Optional parts are added to query string and to args upon here

if(!authorName.isEmpty()){
    queryString += " WHERE";
    queryString += " author_name LIKE ?%";
    args.add(authorName);
    containsCondition = true;
}

if(fromDate!=null){

    if (containsCondition) {
        queryString += " AND";
    } else {
        queryString += " WHERE";
        containsCondition = true;
    }

    queryString += " publication_date AFTER ?";
    args.add(fromDate.getTime());
}

if(toDate!=null){

    if (containsCondition) {
        queryString += " AND";
    } else {
        queryString += " WHERE";
        containsCondition = true;
    }

    queryString += " publication_date BEFORE ?";
    args.add(toDate.getTime());
}

// End of query string
queryString += ";";


Étape 3: effectuer une requête

SimpleSQLiteQuery query = new SimpleSQLiteQuery(queryString, args.toArray());
List<Book> result = booksDao.getBooks(query);




Remarques

  • Comme d'habitude Query, RawQuery prend en charge le renvoi de curseurs, entités, POJO et POJO bruts avec des champs incorporés
  • RawQuery prend en charge les relations
4
Anees

Utilisez SupportSQLiteQuery.

https://developer.Android.com/reference/Android/Arch/persistence/db/SupportSQLiteQuery

La dernière version 1.1.1 utilise maintenant SupportSQLiteQuery.

Une requête avec des liaisons typées. Il est préférable d’utiliser cette API au lieu de rawQuery (String, String []) car il autorise le type de liaison safe paramètres.

@Dao
     interface RawDao {
         @RawQuery(observedEntities = User.class)
         LiveData<List<User>> getUsers(SupportSQLiteQuery query);
     }

Usage:

     LiveData<List<User>> liveUsers = rawDao.getUsers( new 
SimpleSQLiteQuery("SELECT * FROM User ORDER BY name DESC"));

Mettez à jour votre note à 1.1.1

implementation 'Android.Arch.persistence.room:runtime:1.1.1'
implementation 'Android.Arch.lifecycle:extensions:1.1.1'
annotationProcessor "Android.Arch.persistence.room:compiler:1.1.1"

Remarque: si vous effectuez une mise à niveau vers la version 1.1.1 et utilisez String au lieu de SupportSQLiteQuery,

vous obtiendrez l'erreur:

RawQuery n'autorise plus le passage d'une chaîne. Veuillez utiliser Android.Arch.persistence.db.SupportSQLiteQuery.

Utiliser SupportSQLiteQuery comme ci-dessus résoudra le problème.

Remarque: Assurez-vous de bien transmettre le paramètre de requête SupportSQLiteQuery ou vous obtiendrez cette erreur:

Les méthodes RawQuery doivent avoir 1 et 1 seul paramètre de type String ou SupportSQLiteQuery

4
live-love
make it more simple.i will show you example using where clause using two variable.Do 
like this

  @Query("SELECT * FROM Student WHERE stdName1= :myname AND stdId1=:myid")
List<Student> fetchAllData(String myname,int myid);

stdName1 et stdId1 sont des noms de colonnes

1
Syed Danish Haider