如何使用 GRDB 将项目添加到结构中但不在 Db table 中的数组中
How to add items into an array that are in the struct but not in the Db table using GRDB
在 Db 的 My_Quotes table(参见下面的 MyQuotes 结构)中,我存储了从设备上的用户联系人中选择的联系人 ID。这样,如果联系人信息发生更改,ID 将保持不变。因此,我从 Db 中的 My_Quotes table 中提取 ContactID,并使用它通过 func get_ContactName_Org.
构建 ContactFullName、ContactFirst、ContactLast 和 ContactOrg
我遇到的问题是 ContactFullName、ContactFirst、ContactLast 和 ContactOrg(请参阅下面的 QuoteList 结构)不在 My_Quotes table 中。错误是:致命错误:无法从缺少的列 ContactFullName
中读取字符串
我理解错误,但将这些项目添加到 My_Quotes table 会导致许多其他问题。
如何将这些项目插入到数组中?
var theArray = [QuoteList]()
do {
try dbQueue_GRDB.read { db in
for quotes in try QuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID")
{
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
theArray.append(QuoteList(QuoteID: quotes.QuoteID,
Quote_Number: quotes.Quote_Number,
Quote_Status: quotes.Quote_Status,
ContactID: quotes.ContactID,
ContactFullName: fullString, // This is not in the My_Quotes table
ContactFirst: first, // This is not in the My_Quotes table
ContactLast: last, // This is not in the My_Quotes table
ContactOrg: org, // This is not in the My_Quotes table
Inv_ID: quotes.Inv_ID,
Locked_Bool: quotes.Locked_Bool))
}
}
} catch {
print("Couldn't populate the quote list! \(error)")
}
static func get_ContactName_Org(contactID: String) -> (firstName: String, lastName: String, clientOrg: String, fullStaring: String)
{
let store = CNContactStore()
var theName = CNContact()
var theStaring: String = ""
var firstName: String = ""
var lastName: String = ""
var clientOrg: String = ""
do {
theName = try store.unifiedContact(withIdentifier: contactID, keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)])
} catch {
print("Fetching contact data failed: \(error)")
}
firstName = theName.givenName
lastName = theName.familyName
clientOrg = theName.organizationName
theStaring = theName.organizationName == "" ? theName.givenName + " " + theName.familyName : theName.givenName + " " + theName.familyName + ", " + theName.organizationName
return (firstName,lastName,clientOrg,theStaring)
}
struct QuoteList: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Status: String
var ContactID: String
var ContactFullName: String // This is not in the My_Quotes table
var ContactFirst: String // This is not in the My_Quotes table
var ContactLast: String // This is not in the My_Quotes table
var ContactOrg: String // This is not in the My_Quotes table
var Inv_ID: Int64?
var Locked_Bool: String
}
struct MyQuotes: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Date: String
var Quote_Status: String
var NumOf_People: String?
var Event_Venue: String?
var Routine_ID: Int64?
var Routine_Price: Double?
var Quote_Deposit: Double?
var Deposit_Date: String?
var Age_Range: String?
var Lodging_Exp: Double?
var Gas_Exp: Double?
var Meals_Exp: Double?
var Miscel_Exp: Double?
var Airfare_Exp: Double?
var Show_Start: String?
var Show_End: String?
var Show_Date: String?
var Notes_Exp: String?
var ContactID: String
var Quote_Rejection: String?
var Inv_ID: Int64?
var Quote_Discount: Int?
var Locked_Bool: String
}
首先,没有QuoteList
采纳FetchableRecord
。为什么?因为数据库行没有包含足够的信息来构建 QuoteList
。 FetchableRecord
带有一个 init(row: Row)
初始值设定项,无法正确实现,正如致命错误告诉您的那样。让 QuoteList
采用 FetchableRecord
并向其提供不包含足够信息的数据库行是程序员的错误。
FetchableRecord
是一个协议,自带方便的抓取方式,这就是你被它吸引的原因。但现在很明显 QuoteList
需要其他东西,是时候以不同的方式获取 。
一种可能的技术是获取原始数据库行:
// Instead of:
// for quotes in try QuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID")
for rows in try Row.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID") {
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
let quoteList = QuoteList(
QuoteID: row["QuoteID"],
Quote_Number: row["Quote_Number"],
Quote_Status: row["Quote_Status"],
ContactID: row["ContactID"],
ContactFullName: fullString,
ContactFirst: first,
ContactLast: last,
ContactOrg: org,
Inv_ID: row["Inv_ID"],
Locked_Bool: row["Locked_Bool"])
theArray.append(quoteList)
}
另一种技术是定义一个实际可获取的模型:
struct PartialQuoteList: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Status: String
var ContactID: String
var Inv_ID: Int64?
var Locked_Bool: String
}
for partial in try PartialQuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID") {
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
let quoteList = QuoteList(
QuoteID: partial.QuoteID,
Quote_Number: partial.Quote_Number,
Quote_Status: partial.Quote_Status,
ContactID: partial.ContactID,
ContactFullName: fullString,
ContactFirst: first,
ContactLast: last,
ContactOrg: org,
Inv_ID: partial.Inv_ID
Locked_Bool: partial.Locked_Bool)
theArray.append(quoteList)
}
在 Db 的 My_Quotes table(参见下面的 MyQuotes 结构)中,我存储了从设备上的用户联系人中选择的联系人 ID。这样,如果联系人信息发生更改,ID 将保持不变。因此,我从 Db 中的 My_Quotes table 中提取 ContactID,并使用它通过 func get_ContactName_Org.
构建 ContactFullName、ContactFirst、ContactLast 和 ContactOrg我遇到的问题是 ContactFullName、ContactFirst、ContactLast 和 ContactOrg(请参阅下面的 QuoteList 结构)不在 My_Quotes table 中。错误是:致命错误:无法从缺少的列 ContactFullName
中读取字符串我理解错误,但将这些项目添加到 My_Quotes table 会导致许多其他问题。 如何将这些项目插入到数组中?
var theArray = [QuoteList]()
do {
try dbQueue_GRDB.read { db in
for quotes in try QuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID")
{
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
theArray.append(QuoteList(QuoteID: quotes.QuoteID,
Quote_Number: quotes.Quote_Number,
Quote_Status: quotes.Quote_Status,
ContactID: quotes.ContactID,
ContactFullName: fullString, // This is not in the My_Quotes table
ContactFirst: first, // This is not in the My_Quotes table
ContactLast: last, // This is not in the My_Quotes table
ContactOrg: org, // This is not in the My_Quotes table
Inv_ID: quotes.Inv_ID,
Locked_Bool: quotes.Locked_Bool))
}
}
} catch {
print("Couldn't populate the quote list! \(error)")
}
static func get_ContactName_Org(contactID: String) -> (firstName: String, lastName: String, clientOrg: String, fullStaring: String)
{
let store = CNContactStore()
var theName = CNContact()
var theStaring: String = ""
var firstName: String = ""
var lastName: String = ""
var clientOrg: String = ""
do {
theName = try store.unifiedContact(withIdentifier: contactID, keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)])
} catch {
print("Fetching contact data failed: \(error)")
}
firstName = theName.givenName
lastName = theName.familyName
clientOrg = theName.organizationName
theStaring = theName.organizationName == "" ? theName.givenName + " " + theName.familyName : theName.givenName + " " + theName.familyName + ", " + theName.organizationName
return (firstName,lastName,clientOrg,theStaring)
}
struct QuoteList: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Status: String
var ContactID: String
var ContactFullName: String // This is not in the My_Quotes table
var ContactFirst: String // This is not in the My_Quotes table
var ContactLast: String // This is not in the My_Quotes table
var ContactOrg: String // This is not in the My_Quotes table
var Inv_ID: Int64?
var Locked_Bool: String
}
struct MyQuotes: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Date: String
var Quote_Status: String
var NumOf_People: String?
var Event_Venue: String?
var Routine_ID: Int64?
var Routine_Price: Double?
var Quote_Deposit: Double?
var Deposit_Date: String?
var Age_Range: String?
var Lodging_Exp: Double?
var Gas_Exp: Double?
var Meals_Exp: Double?
var Miscel_Exp: Double?
var Airfare_Exp: Double?
var Show_Start: String?
var Show_End: String?
var Show_Date: String?
var Notes_Exp: String?
var ContactID: String
var Quote_Rejection: String?
var Inv_ID: Int64?
var Quote_Discount: Int?
var Locked_Bool: String
}
首先,没有QuoteList
采纳FetchableRecord
。为什么?因为数据库行没有包含足够的信息来构建 QuoteList
。 FetchableRecord
带有一个 init(row: Row)
初始值设定项,无法正确实现,正如致命错误告诉您的那样。让 QuoteList
采用 FetchableRecord
并向其提供不包含足够信息的数据库行是程序员的错误。
FetchableRecord
是一个协议,自带方便的抓取方式,这就是你被它吸引的原因。但现在很明显 QuoteList
需要其他东西,是时候以不同的方式获取 。
一种可能的技术是获取原始数据库行:
// Instead of:
// for quotes in try QuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID")
for rows in try Row.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID") {
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
let quoteList = QuoteList(
QuoteID: row["QuoteID"],
Quote_Number: row["Quote_Number"],
Quote_Status: row["Quote_Status"],
ContactID: row["ContactID"],
ContactFullName: fullString,
ContactFirst: first,
ContactLast: last,
ContactOrg: org,
Inv_ID: row["Inv_ID"],
Locked_Bool: row["Locked_Bool"])
theArray.append(quoteList)
}
另一种技术是定义一个实际可获取的模型:
struct PartialQuoteList: Codable, FetchableRecord
{
let QuoteID: Int64
var Quote_Number: String
var Quote_Status: String
var ContactID: String
var Inv_ID: Int64?
var Locked_Bool: String
}
for partial in try PartialQuoteList.fetchAll(db, sql: "SELECT * FROM My_Quotes ORDER BY QuoteID") {
let fullString = ModelData.get_ContactName_Org(contactID: quotes.ContactID).fullStaring
let first = ModelData.get_ContactName_Org(contactID: quotes.ContactID).firstName
let last = ModelData.get_ContactName_Org(contactID: quotes.ContactID).lastName
let org = ModelData.get_ContactName_Org(contactID: quotes.ContactID).clientOrg
let quoteList = QuoteList(
QuoteID: partial.QuoteID,
Quote_Number: partial.Quote_Number,
Quote_Status: partial.Quote_Status,
ContactID: partial.ContactID,
ContactFullName: fullString,
ContactFirst: first,
ContactLast: last,
ContactOrg: org,
Inv_ID: partial.Inv_ID
Locked_Bool: partial.Locked_Bool)
theArray.append(quoteList)
}