我正在尝试构建一个模型,您可以在其中将节目添加到观看列表并查看它们。当您将节目添加到监视列表或查看它时,如果它尚不存在,我将在数据库中创建一个新节目,否则我将检索它并更新它。 我的问题是,当我检索现有节目并向数据库插入新的监视列表项或评论时,它会引发错误“非法尝试在不同上下文中的对象之间建立关系”。据我了解,这是因为观看列表项或评论在节目存在时尚不存在。 但我不知道如何解决这种行为。我每次都尝试创建一个新节目,但是当我通过监视列表项或评论的关系插入它时,它总是创建一个新节目,而不是更新(如果有现有节目)。 这是我的实现,感谢您的帮助
@Model
final class LocalWatchlistItem {
var addedAt: Date
var show: LocalShow
init(show: LocalShow, addedAt: Date = .now) {
self.show = show
self.addedAt = addedAt
}
}
@Model
final class LocalReview {
var show: LocalShow
...
init(show: LocalShow, ...) {
self.show = show
...
}
}
@Model
final class LocalShow: Showable {
@Attribute(.unique) var id: String
...
@Relationship(deleteRule: .cascade, inverse: \LocalWatchlistItem.show) var watchlistItem: LocalWatchlistItem? = nil
@Relationship(deleteRule: .cascade, inverse: \LocalReview.show) var reviews = [LocalReview]()
init(
id: String,
...
) {
self.id = id
...
}
func upsertShow(_ show: Show) throws -> LocalShow {
if let existingShow = try getShow(show.key) {
existingShow.updatedAt = .now
existingShow.title = show.title
...
return existingShow
} else {
return LocalShow(
id: show.key,
createdAt: .now,
updatedAt: nil,
title: show.title,
...
)
}
}
func addToWatchlist(_ show: Show) throws -> LocalWatchlistItem {
let upsertedShow = try upsertShow(show)
let watchlistItem = LocalWatchlistItem(show: upsertedShow)
database.insert(watchlistItem)
return watchlistItem
}
func createReview(for show: Show, rating: Int, comment: String?) throws -> LocalReview {
let upsertedShow = try upsertShow(show)
let review = LocalReview(show: upsertedShow, rating: rating, comment: comment)
database.insert(review)
return review
}
我找到了一种解决方法,方法是在“LocalWatchlistItem”和“LocalReview”上将“show”设为可选,并按如下方式修改我的函数:
func addToWatchlist(_ show: Show) throws -> LocalWatchlistItem {
let upsertedShow = try upsertShow(show)
let watchlistItem = LocalWatchlistItem()
database.insert(watchlistItem)
watchlistItem.show = upsertedShow
return watchlistItem
}
func createReview(for show: Show, rating: Int, comment: String?) throws -> LocalReview {
let upsertedShow = try upsertShow(show)
let review = LocalReview(rating: rating, comment: comment)
database.insert(review)
review.show = upsertedShow
return review
}
逻辑是根据节目是否存在来插入或更新节目,插入没有任何关系的“watchlistItem”,最后在两个模型都在 modelContext 中时更新关系。通过这种方法,我确保永远不会出现“LocalShow”的重复项,并且不会引发错误“非法尝试在不同上下文中的对象之间建立关系”,因为两个对象都已正确插入。
一般来说,在 SwiftData 中处理任何类型的关系时,我现在建议始终首先插入模型或检索模型,然后更新关系。唯一的缺点是需要对关系进行选择。