Swift SQLite3语法和绑定
首先,这些是我的功能:
>插入功能 func insert(book : Book) throws -> Bool { var insertPointer: OpaquePointer? = nil let query = "INSERT INTO BOOK (bookName,bookAuthor,bookDesc,bookDate,bookImg,createdBy) VALUES (?,?,?)" defer{ sqlite3_finalize(insertPointer) } if sqlite3_prepare_v2(db,query,-1,&insertPointer,nil) == SQLITE_OK { sqlite3_bind_text(insertPointer,1,book.bookTitle,nil) sqlite3_bind_text(insertPointer,2,book.bookAuthor,3,book.bookDesc,nil) //sqlite3_bind_date(insertPointer,4,book.bookDate,nil) //sqlite3_bind_image(insertPointer,5,book.bookImg,6,book.createdBy,nil) guard sqlite3_step(insertPointer) == SQLITE_DONE else { throw SQLiteError.Step(message: errorMessage) } } else { throw SQLiteError.Prepare(message: errorMessage) } return true } >更新功能 func update(book : Book) throws -> Bool { var updatePointer: OpaquePointer? = nil var query = "UPDATE Book SET bookName = ?,bookAuthor = ?,bookDesc = ?,bookDate = ?,bookImg = ?,createdBy = ?,WHERE bookId = ?" defer{ sqlite3_finalize(updatePointer) } if sqlite3_prepare_v2(db,&updatePointer,nil) == SQLITE_OK { sqlite3_bind_text(updatePointer,nil) sqlite3_bind_text(updatePointer,nil) //sqlite3_bind_date(updatePointer,nil) //sqlite3_bind_image(updatePointer,7,book.bookId,nil) guard sqlite3_step(updatePointer) == SQLITE_DONE else { throw SQLiteError.Step(message: errorMessage) } } else { throw SQLiteError.Prepare(message: errorMessage) } return true } >删除功能 func delete(book : Book) throws -> Bool { var deletePointer: OpaquePointer? = nil var query = "DELETE FROM Book WHERE bookId = ?" defer{ sqlite3_finalize(deletePointer) } if sqlite3_prepare_v2(db,&deletePointer,nil) == SQLITE_OK { sqlite3_bind_text(updatePointer,nil) guard sqlite3_step(deletePointer) == SQLITE_DONE else { throw SQLiteError.Step(message: errorMessage) } } else { throw SQLiteError.Prepare(message: errorMessage) } return true } 我有一个像这样的Book类: class Book{ var bookId : Int var bookImg : Data var bookTitle : String var bookAuthor : String var bookDesc : String var bookDate : Date var createdBy : String init(bookId : Int,bookImg : Data,bookTitle : String,bookAuthor : String,bookDesc : String,bookDate : Date,createdBy : String){ self.bookId = bookId self.bookImg = bookImg self.bookTitle = bookTitle self.bookAuthor = bookAuthor self.bookDesc = bookDesc self.bookDate = bookDate self.createdBy = createdBy } } 我是Swift和SQLite的新手.我的问题是: >我是否正确使用参数绑定? 任何帮助将不胜感激! 解决方法
您询问:
大部分. >绑定字符串时,使用SQLITE_TRANSIENT作??为sqlite3_bind_text和sqlite3_bind_blob的最后一个参数可能是谨慎的,如下所述: internal let SQLITE_STATIC = unsafeBitCast(0,to: sqlite3_destructor_type.self) internal let SQLITE_TRANSIENT = unsafeBitCast(-1,to: sqlite3_destructor_type.self) >绑定bookId时,您想使用sqlite3_bind_int64. 然后你问:
重新日期类型,SQLite没有本机日期类型(请参阅http://sqlite.org/datatype3.html).或者: >如果您不需要毫秒,请使用ISODateFormatter构建字符串,并绑定字符串; 以前的字符串替代方法最容易使用,并且在第三方工具中直观地检查数据库时非常容易. timeIntervalSince1970可以说有点效率,但它只是意味着你需要使用unixepoch将双精度转换为可理解的日期,如果查看第三方SQLite工具中的列,这可能有点麻烦.这是效率与可用性之间的权衡. 重新数据,使用sqlite3_bind_blob插入. 几个最后的小观察: >您在sqlite3_prepare_v2之前推迟了sqlite3_finalize.你应该在sqlite3_prepare_v2之后推迟它.如果准备成功,您应该只是最终确定,而不是如果失败. 无论如何,把它拉到一起,你会得到类似的东西: var dateFormatter: DateFormatter = { let _formatter = DateFormatter() _formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSX" _formatter.locale = Locale(identifier: "en_US_POSIX") _formatter.timeZone = TimeZone(secondsFromGMT: 0) return _formatter }() var errorMessage: String { return String(cString: sqlite3_errmsg(db)) } func insert(book: Book) throws { var statement: OpaquePointer? = nil let query = "INSERT INTO book (bookName,?)" guard sqlite3_prepare_v2(db,&statement,nil) == SQLITE_OK else { throw SQLiteError.prepare(message: errorMessage) } defer { sqlite3_finalize(statement) } guard sqlite3_bind_text(statement,book.title,SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_bind_text(statement,book.author,book.bookDescription,dateFormatter.string(from: book.createDate),SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard book.image.withUnsafeBytes({ (bytes: UnsafePointer<UInt8>) -> Int32 in sqlite3_bind_blob(statement,bytes,Int32(book.image.count),SQLITE_TRANSIENT) }) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_bind_text(statement,SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_step(statement) == SQLITE_DONE else { throw SQLiteError.step(message: errorMessage) } } func update(book: Book) throws { var statement: OpaquePointer? = nil let query = "UPDATE Book SET bookName = ?,WHERE bookId = ?" guard sqlite3_prepare_v2(db,SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_bind_int64(statement,Int64(book.id)) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_step(statement) == SQLITE_DONE else { throw SQLiteError.step(message: errorMessage) } guard sqlite3_changes(db) > 0 else { throw SQLiteError.noDataChanged } } func delete(book: Book) throws { var statement: OpaquePointer? = nil let query = "DELETE FROM Book WHERE bookId = ?" guard sqlite3_prepare_v2(db,nil) == SQLITE_OK else { throw SQLiteError.prepare(message: errorMessage) } defer { sqlite3_finalize(statement) } guard sqlite3_bind_int64(statement,Int64(book.id)) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_step(statement) == SQLITE_DONE else { throw SQLiteError.step(message: errorMessage) } guard sqlite3_changes(db) > 0 else { throw SQLiteError.noDataChanged } } func select(bookId: Int) throws -> Book { var statement: OpaquePointer? = nil let query = "SELECT bookId,bookName,createdBy FROM Book WHERE bookId = ?" guard sqlite3_prepare_v2(db,Int64(bookId)) == SQLITE_OK else { throw SQLiteError.bind(message: errorMessage) } guard sqlite3_step(statement) == SQLITE_ROW else { throw SQLiteError.step(message: errorMessage) } return try book(for: statement) } func selectAll() throws -> [Book] { var statement: OpaquePointer? = nil let query = "SELECT bookId,createdBy FROM Book" guard sqlite3_prepare_v2(db,nil) == SQLITE_OK else { throw SQLiteError.prepare(message: errorMessage) } defer { sqlite3_finalize(statement) } var books = [Book]() var rc: Int32 repeat { rc = sqlite3_step(statement) guard rc == SQLITE_ROW else { break } books.append(try book(for: statement)) } while rc == SQLITE_ROW guard rc == SQLITE_DONE else { throw SQLiteError.step(message: errorMessage) } return books } func book(for statement: OpaquePointer?) throws -> Book { let bookId = Int(sqlite3_column_int64(statement,0)) guard let bookNameCString = sqlite3_column_text(statement,1) else { throw SQLiteError.column(message: errorMessage) } let bookName = String(cString: bookNameCString) guard let bookAuthorCString = sqlite3_column_text(statement,2) else { throw SQLiteError.column(message: errorMessage) } let bookAuthor = String(cString: bookAuthorCString) guard let bookDescCString = sqlite3_column_text(statement,3) else { throw SQLiteError.column(message: errorMessage) } let bookDesc = String(cString: bookDescCString) guard let bookDateCString = sqlite3_column_text(statement,4) else { throw SQLiteError.column(message: errorMessage) } guard let bookDate = dateFormatter.date(from: String(cString: bookDateCString)) else { throw SQLiteError.invalidDate } let bookImgCount = Int(sqlite3_column_bytes(statement,5)) guard bookImgCount > 0 else { throw SQLiteError.missingData } guard let bookImgBlog = sqlite3_column_blob(statement,5) else { throw SQLiteError.column(message: errorMessage) } let bookImg = Data(bytes: bookImgBlog,count: bookImgCount) guard let createdByCString = sqlite3_column_text(statement,6) else { throw SQLiteError.column(message: errorMessage) } let createdBy = String(cString: createdByCString) return Book(id: bookId,image: bookImg,title: bookName,author: bookAuthor,bookDescription: bookDesc,createDate: bookDate,createdBy: createdBy) } 有了这些定义: struct Book { var id: Int var image: Data var title: String var author: String var bookDescription: String // this is the only one where I kept the `book` prefix,simply because `description` is a reserved name var createDate: Date var createdBy: String } enum SQLiteError: Error { case open(result: Int32) case exec(message: String) case prepare(message: String) case bind(message: String) case step(message: String) case column(message: String) case invalidDate case missingData case noDataChanged } 从Swift 3开始,我更喜欢小写的枚举值. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |