web-dev-qa-db-fra.com

Android Room: comment lire simultanément sur deux tables - colonne duplicate id

Je suis nouveau sur Android Room. Je veux lire d'un tableau et aussi lire d'un tableau connexe. La relation est assez commune. Une table définit les instances. L'autre tableau définit les types. Imaginez une table Animal et une table AnimalType. Presque chaque fois que la table Animal doit être lue, la table AnimalType doit également être lue. Par exemple, nous voulons afficher le nom de l'animal (de la table Animal) et l'icône du singe (de la table AnimalType).

Basé sur un exemple de la documentation Android Room, voici la classe de données pour le modéliser:

public class AnimalWithType {
    @Embedded
    private Animal animal;

    @Embedded
    private AnimalType type;
    ...

Le DAO peut interroger les données avec une seule requête. La pièce doit être suffisamment intelligente pour peupler les deux classes enfants.

@Dao
public interface ZooDao
    @Query("select * from animal join animal_type on (animal.id = animal_type.id)")
    List<AnimalWithType> getAllAnimals();

Comme toujours, la théorie est belle. La réalité est brisée. Le résultat est l'erreur suivante:

Error:(8, 8) error: Multiple fields have the same columnName: id. Field names: animal > id, animalType > id.

Apparemment, Room ne comprend pas qu'une seule colonne "id" dans la requête et la classe à laquelle elle appartient. Il existe deux solutions possibles: 1) Nous pourrions créer un alias de nom de colonne pour building_type.id et en informer Room 2) Nous savons déjà que la clé étrangère de la table Animal à la table AnimalType (peut-être animal_type_id) a l'autre colonne id.

La question est de savoir comment communiquer cela à Room. Room est-il même capable de gérer ce cas?

Des conseils sur la façon de résoudre ce problème sont appréciés. J'espère que Room ne nécessite pas de faire quelque chose de maladroit, comme donner à chaque colonne d'identifiant un nom unique.

10
Thomas Fischer

waqaslam a indiqué la voie à suivre pour trouver la solution. Il a suggéré d'aliaser les noms des colonnes. L'étape supplémentaire consiste à donner un préfixe à la deuxième table.

public class AnimalWithType {
@Embedded
private Animal animal;

@Embedded(prefix = "type_")
private AnimalType type;
...

Les alias de colonne sont longs et compliqués. J'espère que quelqu'un pourra trouver un moyen plus propre.

@Query("select animal.id, animal.name..., animal_type.id as type_id... from animal join animal_type on (animal.id = animal_type.id)")
4
Thomas Fischer

Au lieu d'utiliser * pour collecter tous les champs, vous devez fournir des noms de colonne spécifiques, carid se trouve dans les deux tables, ce qui provoque l'erreur. Modifiez votre requête en quelque chose comme:

select animal.id AS 'ID', animal.columnA, animal.columnB,
animal_type.columnA, animal_type.columnB from animal
join animal_type on (animal.id = animal_type.id)

Vous n'avez pas besoin d'extraire les identifiants des deux tables car ils seront identiques, un seul suffit. Cependant, remplacez coulmnA, columnB, etc. par les noms de colonne valides que vous voulez extraire.

1
waqaslam

J'ai résolu ce problème en ajoutant un préfixe aux noms de colonne afin qu'ils soient uniques. Si votre cas n'autorise pas la modification des noms de colonne, utilisez certaines des réponses fournies et l'annotation @Embedded (préfixe).

@Entity(tableName = "animal")
public class Animal {
    @PrimaryKey
    @ColumnInfo(name = "animal_id")
    public long id;
    ...
}

@Entity(tableName = "animal_type")
public class AnimalType {
    @PrimaryKey
    @ColumnInfo(name = "animal_type_id")
    public long id;
    ...
}

Et votre requête sera:

SELECT * FROM animal JOIN animal_type ON animal_id = animal_type_id
1
kosev