Dao génériques de classe de base réutilisables avec salle Android

y a-t-il un moyen de créer des DAOs génériques réutilisables de classe de base avec Android Room?

public interface BaseDao<T> {

  @Insert
  void insert(T object);

  @Update
  void update(T object);

  @Query("SELECT * FROM #{T} WHERE id = :id")
  void findAll(int id);

  @Delete
  void delete(T object);

}

public interface FooDao extends BaseDao<FooObject> { ... }

public interface BarDao extends BaseDao<BarEntity> { ... }

Je n'ai pas été en mesure de comprendre n'importe quel moyen d'atteindre ceci sans devoir déclarer les mêmes membres d'interface et écrire la requête pour chaque sous-classe. Lorsqu'on traite avec un grand nombre d'Oad semblables, cela devient très fastidieux...

15
demandé sur pqvst 2017-06-25 15:08:36

4 réponses

aujourd'Hui, 08 août, en 2017, avec la version 1.0.0-alpha8 le Dao ci-dessous fonctionne. Je peux demander à D'autres Dao de jouer les Héros du GenericDao.

@Dao
public interface GenericDao<T> {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(T... entity);

    @Update
    void update(T entity);

    @Delete
    void delete(T entity);
}

cependant, GenericDao ne peut pas être inclus dans ma classe de base de données

7
répondu Natan 2017-08-08 22:00:44

autant que je sache, vous pouvez le faire uniquement pour insert(), update() et delete(), car il ne nécessite pas de déclaration SQL spécifique qui doit être vérifiée au moment de la compilation.

exemple:

BaseDao.java

public interface BaseDao<T> {

    @Insert
    void insert(T obj);

    @Insert
    void insert(T... obj);

    @Update
    void update(T obj);

    @Delete
    void delete(T obj);
}

UserDao.java

@Dao
abstract class UserDao implements BaseDao<User> {

    @Query("SELECT * FROM User")
    abstract List<User> getUser();

}

source

1
répondu Kharda 2018-04-18 16:06:20

j'ai une solution pour findAll.

Codes que BaseDao:

...
public List<T> findAll() {
    SimpleSQLiteQuery query = new SimpleSQLiteQuery(
        "select * from " + getTableName()
    );
    return doFindAll(query);
}
...
public String getTableName() {
    // Below is based on your inheritance chain
    Class clazz = (Class)
        ((ParameterizedType) getClass().getSuperclass().getGenericSuperclass())
            .getActualTypeArguments()[0];
    // tableName = StringUtil.toSnakeCase(clazz.getSimpleName());
    String tableName = clazz.getSimpleName();
    return tableName;
}
...
@RawQuery
protected abstract List<T> doFindAll(SupportSQLiteQuery query);
@Dao
public abstract class UserDao extends AppDao<User> {
}

C'est tout

L'idée est

  1. obtenir le nom de tableau du type générique de la sous-classe à l'exécution
  2. passer ce nom de table à un RawQuery

si vous préférez interface à classe abstraite, vous pouvez essayer la méthode optionnelle de java 8.

ce n'est pas beau mais ça a marché, comme vous pouvez voir.

j'ai créé un résumé ici

1
répondu Clxy 2018-08-12 08:53:38

bien que je sois d'accord avec votre raisonnement, la réponse est non. Et ce pour plusieurs raisons.

  1. quand le fooDao_Impl.java est généré à partir de votre @Dao fooDao extends BaseDao<Foo> class, vous rencontrerez beaucoup d'erreurs" cannot find class Symbol T". Ceci est dû à la méthode utilisée pour générer les implémentations dao. Il s'agit d'une méthode qui n'appuiera pas votre résultat souhaité, et il est peu probable de changer bientôt (à mon avis, en raison de l'effacement de type).

  2. Même si c'est résolu, la pièce ne supporte pas la dynamique @Dao requêtes, dans un effort pour empêcher L'injection SQL. Cela signifie que vous ne pouvez insérer dynamiquement des valeurs dans les requêtes, pas les noms de colonne, les noms de tables ou de requêtes. Dans l'exemple que vous avez vous ne pourriez pas utiliser #{T} car cela violerait ce principe. En théorie, si le problème décrit au point 1 est résolu, vous pouvez utiliser Insérer, Supprimer et mettre à jour.

0
répondu Jack Dalton 2017-07-15 15:44:18