如何在 Realm 中设置自动增量键?
Posted
技术标签:
【中文标题】如何在 Realm 中设置自动增量键?【英文标题】:How do I set a auto increment key in Realm? 【发布时间】:2014-12-02 20:23:31 【问题描述】:每个 ChatData 对象都有一个唯一的 msgid。
@interface ChatData : RLMObject
@property NSInteger msgid;
....
@end
但是每次我创建一个新对象时,我都必须查询所有对象并获取最后一个 msgid。
RLMArray *all = [[ChatData allObjects] arraySortedByProperty:@"msgid" ascending:YES];
ChatData *last = [all lastObject];
ChatData *newData = [[ChataData alloc]init];
newData.msgid = last.msgid+1;
有没有一种有效的方法来替换这个实现?
【问题讨论】:
【参考方案1】:Realm 没有自动递增行为,因此您需要自行管理。我鼓励您就您的数据问自己一个问题:
是否必须有连续的、连续的整数 ID?
如果不是,那么唯一的字符串主键可能就足够了。然后你可以使用[[NSUUID UUID] UUIDString]
之类的东西来生成唯一的字符串ID。这样做的好处是,这些 UUID 或多或少保证是唯一的,即使在多线程场景中也是如此。
如果是这样,则始终将最后一个数字保留在内存中可能会更有效,这样就不必在每次生成新 ID 时都进行查询。如果对象可能在多个线程中创建,请确保您的 nextPrimaryKey()
函数是线程安全的,否则它可能会生成两次(或更多!)相同的数字。
【讨论】:
是否有计划向 Realm 添加自动增量行为? 是的,该功能即将推出,但我没有给你的时间表。 把这个放在+defaultPropertyValues
字典里没问题吧?我指的是[[NSUUID UUID] UUIDString]
。
对于 Swift 使用这个NSUUID().UUIDString
checkout github.com/realm/realm-cocoa/issues/2591#issuecomment-170259579 如果有人关心 Realm 自动增量功能【参考方案2】:
您正在将此代码用于 Swift 中的自动增量主键:
var myvalue = realm.objects(ChatData).map$0.id.maxElement() ?? 0
myvalue = myvalue + 1
【讨论】:
应用程序因“插入对象后无法更改主键”错误而终止。更新主键的任何替代方法? 很好的解决方案。像魅力一样工作。谢谢你:) func nextId() -> Int return (realm?.objects(MyRealmObject.self).map$0.id.max() ?? 0) + 1 【参考方案3】:Swift 2.0 中的自动增量 id 领域: 在类领域插入代码和对象写入使用
import Foundation
import RealmSwift
class Roteiro: Object
dynamic var id = 0
dynamic var Titulo = ""
dynamic var Observacao = ""
dynamic var status = false
dynamic var cadastrado_dt = NSDate()
override static func primaryKey() -> String?
return "id"
//Incrementa ID
func IncrementaID() -> Int
let realm = try! Realm()
if let retNext = realm.objects(Roteiro.self).sorted(byKeyPath: "id").first?.id
return retNext + 1
else
return 1
在文件中写入使用:
let Roteiro_Add = Roteiro()
//increment auto id
Roteiro_Add.id = Roteiro_Add.IncrementaID()
Roteiro_Add.Titulo = TituloDest
Roteiro_Add.Observacao = Observacao
Roteiro_Add.status = false
let realm = try! Realm()
try! realm.write( () -> Void in
realm.add([Roteiro_Add])
)
【讨论】:
谢谢兄弟 :) 又快又好! 是的,多线程读写可能存在一些问题。这可能需要一些额外的过程。 if let retNext = realm.objects(Roteiro.self).sorted(byKeyPath: "id").first?.id 这应该是最后一项,例如 if let retNext = realm.objects(Ordernew .self).sorted(byKeyPath: "id").last?.id 【参考方案4】:在 Realm 中,您需要自行管理 auto-inc ID,因此有很多方法可以管理它。以下是其中的一些。
func incrementID() -> Int
let realm = try! Realm()
return (realm.objects(Person.self).max(ofProperty: "id") as Int? ?? 0) + 1
每次添加记录时调用此方法。
【讨论】:
我收到此错误“插入对象后无法更改主键”@Tofaani Kaanudo【参考方案5】:我在我的模型中使用了 creationDate,所以我根据这个日期创建了一个 Unix timeStamp,并将其用作我的对象的 primaryKey。
保证 99.99% 是唯一的在我的情况下(因为时间戳精确到秒),但这可能取决于您的用例。 它不如 UUID 健壮,但在许多情况下就足够了。
extension NSDate
/** Returns a NSDate instance from a time stamp */
convenience init(timeStamp: Double)
self.init(timeIntervalSince1970: timeStamp)
extension Double
/** Returns a timeStamp from a NSDate instance */
static func timeStampFromDate(date: NSDate) -> Double
return date.timeIntervalSince1970
【讨论】:
【参考方案6】:这基本上是 jpsim 的答案中所建议的,使用 UUID
生成唯一密钥。我们在插入之前进行查询以确保唯一性。这通常只会引发一个查询;在非常罕见的碰撞情况下,它会一直持续到找到唯一的 id 为止。这个解决方案是对Realm
类型的自然扩展,并且对继承自Object
的类是通用的。该类必须实现 primaryKey
并返回 String
属性的名称。
extension Realm
func createAutoUnique<T: Object>(_ type: T.Type) -> T
guard let primaryKey = T.primaryKey() else
fatalError("createAutoUnique requires that \(T.self) implements primaryKey()")
var id: String
var existing: T? = nil
repeat
id = UUID().uuidString
existing = object(ofType: type, forPrimaryKey: id)
while (existing != nil)
let value = [
primaryKey: id
]
return create(type, value: value, update: false)
【讨论】:
以上是关于如何在 Realm 中设置自动增量键?的主要内容,如果未能解决你的问题,请参考以下文章
hibernate - 如何在 mysql 和 oracle 数据库中设置自动增量?
如何在 Realm 中设置 NSPredicate 以找到 totalPrice > X?