我正在使用SwiftData和SwiftUI,xcode 15 beta 5。我试图在DB中建立实体之间的关系。这是一个用户,一本书,以及它们之间的所有权。
struct asdApp: App {
let container = try! ModelContainer(for: [Ownership.self, User.self, Book.self])
var body: some Scene {
WindowGroup {
ContentView()
.task {
let jon = User()
container.mainContext.insert(jon)
let book = Book()
container.mainContext.insert(book)
let o = Ownership(keeper: jon, book: book) // <-- crash here!!
container.mainContext.insert(o)
}
}
.modelContext(container.mainContext)
}
}
字符串
下面是模型,这样你就有了完整的代码:
@Model
final class User {
@Attribute(.unique) let id: UUID
init(id: UUID = UUID()) {
self.id = id
}
}
@Model
final class Book {
@Attribute(.unique) let id: UUID
init(id: UUID = UUID()) {
self.id = id
}
}
@Model
final class Ownership {
@Attribute(.unique) var id: UUID
var keeper: User
var book: Book
init(id: UUID = UUID(), keeper: User, book: Book) {
self.id = id
self.keeper = keeper
self.book = book
}
}
型
以下是完整的错误:
Thread 1: "Illegal attempt to establish a relationship 'keeper' between objects in different contexts (source = <NSManagedObject: 0x60000212e5d0> (entity: Ownership; id: 0x600000243560 <x-coredata:///Ownership/tFADECEE1-82F7-4071-93B1-259354AE2E2A4>; data: {\n book = nil;\n id = \"6A63596F-66C2-45B3-91C0-FF24FF88B1B5\";\n keeper = nil;\n}) , destination = <NSManagedObject: 0x60000214fed0> (entity: User; id: 0x600000299180 <x-coredata:///User/tFADECEE1-82F7-4071-93B1-259354AE2E2A2>; data: {\n id = \"59B5122C-5CC6-4105-8F11-D48B6D46E63D\";\n}))"
型
第一个问题:只有一个上下文,那么为什么会崩溃?
如果我像这样更改顺序,则不会出现错误:
var body: some Scene {
WindowGroup {
ContentView()
.task {
let jon = User()
let book = Book()
let o = Ownership(keeper: jon, book: book)
container.mainContext.insert(jon)
container.mainContext.insert(book)
container.mainContext.insert(o)
}
}
.modelContext(container.mainContext)
}
型
但它并不正确,因为它创建了一本额外的书。下面是我如何发现的:
@main
struct asdApp: App {
let container = try! ModelContainer(for: [Ownership.self, User.self, Book.self])
var body: some Scene {
WindowGroup {
ContentView()
.task {
clearAll(modelContainer: container)
let context = container.mainContext
let jon = User()
let book = Book()
let o = Ownership(keeper: jon, book: book)
context.insert(jon)
context.insert(book)
context.insert(o)
do {
for (index, user) in try context.fetch(FetchDescriptor<User>()).enumerated() {
print("\(index) [USER]: id: \(user.id)")
}
for (index, user) in try context.fetch(FetchDescriptor<Book>()).enumerated() {
print("\(index) [BOOK]: id: \(user.id)")
}
for (index, user) in try context.fetch(FetchDescriptor<Ownership>()).enumerated() {
print("\(index) [OWN]: id: \(user.id)")
}
} catch {
fatalError("Error while fetching all entities: \(error)")
}
}
}
.modelContext(container.mainContext)
}
@MainActor
func clearAll(modelContainer: ModelContainer) {
do {
(try modelContainer.mainContext.fetch(FetchDescriptor<User>()))
.forEach {
modelContainer.mainContext.delete($0)
}
(try modelContainer.mainContext.fetch(FetchDescriptor<Book>()))
.forEach {
modelContainer.mainContext.delete($0)
}
(try modelContainer.mainContext.fetch(FetchDescriptor<Ownership>()))
.forEach {
modelContainer.mainContext.delete($0)
}
try modelContainer.mainContext.save()
} catch {
fatalError("Error while fetching all entities: \(error)")
}
}
}
型
下面是输出:
0 [USER]: id: 14B69B68-1123-4658-9399-7E60E1051A2D
0 [BOOK]: id: 3A52F512-E82F-4574-B2EF-A0B9258EA094
1 [BOOK]: id: 99FC93F5-B81F-4060-A549-869472E53D1D
0 [OWN]: id: 7F1D089A-AF00-4AB0-A17A-275E8448FC20
型
第二个问题:如果我只调用init一次(在调试期间它只出现一次),为什么有两本书,它们是如何得到不同的id的?我想要一本书,一个用户和一个关系。
实际的例子更复杂,这是我能达到的最低限度。
2条答案
按热度按时间mfpqipee1#
在App.swift文件的WindowGroup后面添加这样的模型容器。modelContainer(for:[Ownership.self,User.self,Book.self])//SwiftData会推断出上面数组中的项的依赖关系,所以不需要全部添加,但如果需要可以
将SwiftData假设的模型上下文传递到需要它的文件中:@Environment(.modelContext)var modelContext然后像这样添加:modelContext.insert(objectNameHere)
book存在两次,因为你在类中初始化它,然后在所有权中再次调用它。
vybvopom2#
我找到的解决方案是在
Ownership.init()
之外初始化keeper
和user
变量属性我是说
字符串