【问题标题】:How do I set a auto increment key in Realm?如何在 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;

有没有一种有效的方法来替换这个实现?

【问题讨论】:

    标签: ios realm


    【解决方案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)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2017-03-03
        • 2017-08-13
        • 1970-01-01
        • 1970-01-01
        • 2011-12-04
        • 1970-01-01
        • 2020-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多