在 CoreData 中保存复杂的关系数据
Save complex relational data in CoreData
我回到了使用 CoreData 的 SwiftUI 学习课程。我有三个实体:
User // Has many Customers
Customer // Belongs to User and has many PartExchanges
PartExchange // Belongs to customer
当用户登录后首次安装应用程序时,我会获取一些要保存的初始数据(以上:客户、零件交换等...):
struct AuthResponse: Decodable {
let error: String?
let token: String?
let userData: UserObject?
let customers: [Customers]?
struct UserObject: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let UserID: String
}
struct Customers: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let Customer_ID: String
let PartExchanges: [PartExchangeData]?
}
}
// In another file and not inside AuthResponse
struct PartExchangeData: Decodable {
let Registration: String?
let Customer_ID: String?
let PartExchange_ID: String?
let Variant: String?
let Colour: String?
}
AuthResponse
仅在用户首次登录或重新安装应用程序时使用,以从我们的 API:
获取初始数据
// The exact data I have
import SwiftUI
class AuthController {
var emailUsername: String = ""
var password: String = ""
func login() -> Void {
guard let url = URL(string: "http://localhost:4000/api/auth") else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: AnyHashable] = [
"emailUsername": emailUsername,
"password": password
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
// Make the request
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let decodedResponse = try?
decoder.decode(AuthResponse.self, from: data) {
DispatchQueue.main.async {
if decodedResponse.error != nil {
// Tell user?
return
}
let userObject = UserModel()
userObject.createUser(authObject: decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}
最后,UserModel
:
class UserModel: ObservableObject {
private let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
private let viewContext = PersistenceController.shared.container.viewContext
@Published var saved: Bool = false
var firstName: String = ""
var surname: String = ""
var emailAddress: String = ""
var token: String = ""
var userId: String = ""
init() {...}
public func createUser(authObject: AuthResponse) -> Void {
do {
// Create a user on first login
let user = User(context: viewContext)
let customer = Customer(context: viewContext)
let partExchange = PartExchange(context: viewContext)
//let userCustomers: [AuthResponse.Customers]
user.firstName = authObject.userData!.FirstName
user.surname = authObject.userData!.Surname
user.emailAddress = authObject.userData!.EmailAddress
user.token = authObject.token!
user.userId = authObject.userData!.UserID
// Save customers
for cus in authObject.customers! {
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
// save part exchanges
for px in cus.PartExchanges! {
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch {
let error = error as NSError
// If any issues, rollback? viewContext.rollback()
fatalError("Could not save user: \(error)")
}
}
public func logOut() {
// Only remove the token....
}
}
我在使用这种方法时遇到的问题是保存时;它正在挽救循环中的最后一位客户。
Xcode 为 User
、Customer
和 PartExchnage
生成了一些扩展,在 User
内部,我看到一个函数:@NSManaged public func addToCustomers(_ values: NSSet)
:
[..]
user.addToCustomers(<what-goes-here>)
我的用户实体保存正确。客户只有 api 数组中的最后一个数据。如何正确保存客户多的用户,每个客户有很多零件交换?
您需要为每个循环中的每个迭代创建一个新对象,因为创建的每个对象都将作为单独的项目存储在核心数据中
所以createUser
这样改
public func createUser(authObject: AuthResponse) -> Void {
do {
let user = User(context: viewContext)
user.firstName = authObject.userData!.FirstName
// more properties ...
for cus in authObject.customers! {
let customer = Customer(context: viewContext)
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
for px in cus.PartExchanges! {
let partExchange = PartExchange(context: viewContext)
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch let error = error as NSError {
//Either log the error and return some status or throw it
//FatalError is a bit to much in this situation
fatalError("Could not save user: \(error)")
}
}
我回到了使用 CoreData 的 SwiftUI 学习课程。我有三个实体:
User // Has many Customers
Customer // Belongs to User and has many PartExchanges
PartExchange // Belongs to customer
当用户登录后首次安装应用程序时,我会获取一些要保存的初始数据(以上:客户、零件交换等...):
struct AuthResponse: Decodable {
let error: String?
let token: String?
let userData: UserObject?
let customers: [Customers]?
struct UserObject: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let UserID: String
}
struct Customers: Decodable {
let FirstName: String?
let Surname: String?
let EmailAddress: String?
let Customer_ID: String
let PartExchanges: [PartExchangeData]?
}
}
// In another file and not inside AuthResponse
struct PartExchangeData: Decodable {
let Registration: String?
let Customer_ID: String?
let PartExchange_ID: String?
let Variant: String?
let Colour: String?
}
AuthResponse
仅在用户首次登录或重新安装应用程序时使用,以从我们的 API:
// The exact data I have
import SwiftUI
class AuthController {
var emailUsername: String = ""
var password: String = ""
func login() -> Void {
guard let url = URL(string: "http://localhost:4000/api/auth") else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: AnyHashable] = [
"emailUsername": emailUsername,
"password": password
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)
// Make the request
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let decodedResponse = try?
decoder.decode(AuthResponse.self, from: data) {
DispatchQueue.main.async {
if decodedResponse.error != nil {
// Tell user?
return
}
let userObject = UserModel()
userObject.createUser(authObject: decodedResponse)
}
return
}
}
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
}
最后,UserModel
:
class UserModel: ObservableObject {
private let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
private let viewContext = PersistenceController.shared.container.viewContext
@Published var saved: Bool = false
var firstName: String = ""
var surname: String = ""
var emailAddress: String = ""
var token: String = ""
var userId: String = ""
init() {...}
public func createUser(authObject: AuthResponse) -> Void {
do {
// Create a user on first login
let user = User(context: viewContext)
let customer = Customer(context: viewContext)
let partExchange = PartExchange(context: viewContext)
//let userCustomers: [AuthResponse.Customers]
user.firstName = authObject.userData!.FirstName
user.surname = authObject.userData!.Surname
user.emailAddress = authObject.userData!.EmailAddress
user.token = authObject.token!
user.userId = authObject.userData!.UserID
// Save customers
for cus in authObject.customers! {
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
// save part exchanges
for px in cus.PartExchanges! {
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch {
let error = error as NSError
// If any issues, rollback? viewContext.rollback()
fatalError("Could not save user: \(error)")
}
}
public func logOut() {
// Only remove the token....
}
}
我在使用这种方法时遇到的问题是保存时;它正在挽救循环中的最后一位客户。
Xcode 为 User
、Customer
和 PartExchnage
生成了一些扩展,在 User
内部,我看到一个函数:@NSManaged public func addToCustomers(_ values: NSSet)
:
[..]
user.addToCustomers(<what-goes-here>)
我的用户实体保存正确。客户只有 api 数组中的最后一个数据。如何正确保存客户多的用户,每个客户有很多零件交换?
您需要为每个循环中的每个迭代创建一个新对象,因为创建的每个对象都将作为单独的项目存储在核心数据中
所以createUser
这样改
public func createUser(authObject: AuthResponse) -> Void {
do {
let user = User(context: viewContext)
user.firstName = authObject.userData!.FirstName
// more properties ...
for cus in authObject.customers! {
let customer = Customer(context: viewContext)
customer.firstName = cus.FirstName
customer.surname = cus.Surname
user.addToCustomers(customer)
for px in cus.PartExchanges! {
let partExchange = PartExchange(context: viewContext)
partExchange.registration = px.Registration
partExchange.partExchangeId = px.PartExchange_ID
partExchange.variant = px.Variant
customer.addToPartExchanges(partExchange)
}
}
try viewContext.save()
saved = true
print("ALL SAVED!!")
} catch let error = error as NSError {
//Either log the error and return some status or throw it
//FatalError is a bit to much in this situation
fatalError("Could not save user: \(error)")
}
}