1
votes

Comment modéliser une relation plusieurs-à-plusieurs dans Android Room avec CrossRef Junction

Comment modéliser une relation plusieurs-à-plusieurs comme décrit dans https://developer.android.com/training/data-storage/room/relationships#many-to-many , mais avec une propriété supplémentaire sur la jonction? Je souhaite essentiellement réaliser ce qui suit:

/-- A ---\      /- ACrossB -\            /-- B ---\
|        |      |           |            |        |
| - id   |----->|  - aId    |     |------| - id   |
| - name |      |  - bId    |-----|      |  -name |
|        |      |  - prop   |            |        |
\--------/      \-----------/            \--------/

pour pouvoir y accéder dans mon Dao:

@Dao
interface SongWithPlaylistsDao {
    @Query("SELECT * FROM Song")
    fun list(): LiveData<List<SongWithPlaylists>>
}

Je sais comment, depuis un ERM perspective, vous modéliseriez cette relation comme ceci:

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val playlistName: String
)

@Entity
data class Song(
    @PrimaryKey val songId: Long,
    val songName: String,
    val artist: String
)

@Entity(primaryKeys = ["playlistId", "songId"])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long,
    val rating: Int // <-- the additional property
)

data class PlaylistWithRating(
    val playlist: Playlist,
    val rating: Int // <-- the additional property
)

data class SongWithPlaylists(
    @Embedded val song: Song,
    @Relation(
         parentColumn = "songId",
         entityColumn = "playlistId",
         associateBy = @Junction(PlaylistSongCrossRef::class)
    )
    val playlists: List<PlaylistWithRating>
)

Je sais aussi comment interroger cette relation en utilisant JOIN , mais je n'ai pas pu comprendre la documentation comment faire cela dans Room tout en préservant l'intégrité des données.


5 commentaires

Je veux en savoir plus sur votre propriété supplémentaire évaluation pour quoi? Pour une playlist ou pour une chanson?


La note est pour la combinaison de la chanson et de la liste de lecture. Une chanson peut avoir différentes notes sur différentes listes de lecture.


avez-vous résolu ce problème? J'ai un problème similaire (j'ai besoin de la propriété supplémentaire pour commander les chansons de la playlist)


Non désolé. Je n'ai pas eu le temps de continuer à chercher dans Android Room.


@Jeremy Mon anglais est médiocre, mais j'ai ouvert un problème dans le suivi des problèmes de Google à l'adresse issuetracker.google.com/issues/ 169467510 J'ai rencontré le même problème et la seule solution de contournement que je pense est d'utiliser Sqlite sale


3 Réponses :


0
votes

avez-vous essayé ceci:

@Entity classe de données PlaylistSongCrossRef ( val playlistId: Long, val songId: Long,

 @PrimaryKey(autoGenerate = true)
val rating: Int // <-- the additional property

)

Remarque: je ne sais pas comment déclarer le primaire dans kotlin, je suis développeur java. Mais vous avez l'idée ... La jonction fonctionnera toujours, alors que vous pouvez avoir de nombreuses associations avec la même chanson différenciées par une note unique.


0 commentaires

0
votes

Je pense que vous n'avez pas besoin de créer une nouvelle classe de données PlaylistWithRating . Parce que vous pouvez définir la propriété supplémentaire rating sur entity directement. Par exemple,

Si votre note est pour playlist , vous pouvez définir cette propriété comme suit.

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: Long,
    val playlistName: String,
    val rating: Int // <-- the additional property
)

@Entity
data class Song(
    @PrimaryKey val songId: Long,
    val songName: String,
    val artist: String
)

@Entity(primaryKeys = ["playlistId", "songId"])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

data class PlaylistWithSongs(
    @Embedded val playlist: Playlist,
    @Relation(
         parentColumn = "playlistId",
         entityColumn = "songId",
         associateBy = @Junction(PlaylistSongCrossRef::class)
    )
    val songs: List<Song>
)

data class SongWithPlaylists(
    @Embedded val song: Song,
    @Relation(
         parentColumn = "songId",
         entityColumn = "playlistId",
         associateBy = @Junction(PlaylistSongCrossRef::class)
    )
    val playlists: List<Playlist>
)

Si votre note est pour chanson , vous pouvez définir cette propriété comme suit.

@Entity
data class Song(
    @PrimaryKey val songId: Long,
    val songName: String,
    val artist: String,
    val rating: Int // <-- the additional property
)

Donc, le La relation plusieurs-à-plusieurs de votre schéma comme vous l'avez mentionné document sera correcte. Vous n'avez pas besoin de prendre en compte une classe de données supplémentaire pour la propriété rating .

Donc, cela pourrait être comme suit.

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: Long,
    val playlistName: String,
    val rating: Int // <-- the additional property
)

J'espère que cela vous sera utile.


1 commentaires

tnx pour vos efforts. mais supposons que nous ne pouvons attribuer cet attribut supplémentaire (note dans ce cas) à aucune des entités. J'ai rencontré un problème similaire dont l'attribut supplémentaire est purement pour l'entité associative.



0
votes

J'ai rencontré le même problème et je l'ai finalement résolu d'une autre manière. Il y a des cas où vous ne pouvez pas attribuer un attribut à un côté de la relation binaire de sorte que l'attribut appartient à la relation elle-même.

Étape 1 -> définir l'entité A et l'entité B

@Dao
interface SongWithPlaylistsDao {
    @Query("""
        select Song.songId,Song.songName,Song.artist,Playlist.playlistId,Playlist.playlistName,PlaylistSongCrossRef.rating
        from Song inner join PlaylistSongCrossRef on Song.songId = PlaylistSongCrossRef.songId 
        inner join Playlist on Playlist.playlistId = PlaylistSongCrossRef.playlistId
        """)
    fun list(): LiveData<List<SongWithPlaylists>>
}


0 commentaires