您的关联没有问题。所有hasMany()
和belongsTo()
都是正确的。您收到的错误告诉我您的数据库设置有问题(您的问题中没有包括)。
这是我将如何实现它:
import GRDB
struct Album: Codable, Hashable, FetchableRecord, MutablePersistableRecord {
mutating func didInsert(with rowID: Int64, for column: String?) { id = rowID }
var id: Int64?
var name: String
static let passports = hasMany(AlbumPassport.self)
static let tracks = hasMany(Track.self, through: passports, using: AlbumPassport.track)
}
struct Track: Codable, Hashable, FetchableRecord, MutablePersistableRecord {
mutating func didInsert(with rowID: Int64, for column: String?) { id = rowID }
var id: Int64?
var name: String
static let passports = hasMany(AlbumPassport.self)
static let albums = hasMany(Album.self, through: passports, using: AlbumPassport.album)
}
struct AlbumPassport: Codable, Hashable, FetchableRecord, PersistableRecord {
let track: Int64
let album: Int64
static let track = belongsTo(Track.self)
static let album = belongsTo(Album.self)
}
let queue = DatabaseQueue()
try queue.write { db in
try db.create(table: "album") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
}
try db.create(table: "track") { t in
t.autoIncrementedPrimaryKey("id")
t.column("name", .text).notNull()
}
try db.create(table: "albumPassport") { t in
t.column("track", .integer).notNull().indexed().references("track")
t.column("album", .integer).notNull().indexed().references("album")
t.primaryKey(["track", "album"])
}
// Testing real data from https://music.apple.com/de/artist/yiruma/73406786
var solo = Album(name: "SOLO")
try solo.insert(db)
var sometimes = Track(name: "Sometimes Someone")
try sometimes.insert(db)
try AlbumPassport(track: sometimes.id!, album: solo.id!).insert(db)
var destiny = Track(name: "Destiny Of Love")
try destiny.insert(db)
try AlbumPassport(track: destiny.id!, album: solo.id!).insert(db)
var bestOf = Album(name: "Best of Yiroma")
try bestOf.insert(db)
var poem = Track(name: "Poem")
try poem.insert(db)
try AlbumPassport(track: poem.id!, album: bestOf.id!).insert(db)
var river = Track(name: "River Flows In You")
try river.insert(db)
try AlbumPassport(track: river.id!, album: bestOf.id!).insert(db)
}
// Fetch all albums and their tracks
try queue.read { db in
struct AlbumInfo: FetchableRecord, Decodable, CustomStringConvertible {
var album: Album
var tracks: Set<Track>
var description: String { "\(album.name) → \(tracks.map(\.name))" }
}
let request = Album.including(all: Album.tracks)
let result = try AlbumInfo.fetchAll(db, request)
print(result)
// > [SOLO → ["Sometimes Someone", "Destiny Of Love"], Best of Yiroma → ["River Flows In You", "Poem"]]
}
对于另一个代码示例,请参阅我对多对多关系的回答,其中一个实体具有多个相同类型的属性。