核心数据主键


81

这似乎很愚蠢,但我仍然不知道如何在xcdatamodel文件中将属性标记为主键。我的永久存储是sqlite文件。谁能帮我?

在这种情况下,如何“验证”一个唯一的ID?我应该写一个验证方法之类的吗?

Answers:


91

您的选择是:

  • 使用-[NSManagedObject objectID]。请注意,此ID是临时的,直到第一次保存对象或您调用-[NSManagedObjectContext obtainPermanentIDsForObjects:error:]
  • 使用CFUUID函数族为您的-awakeFromInsert方法中的每个对象生成一个UUID
  • 创建自己的类似于主键的系统,该系统将整数存储在模型中,并随创建每个对象而增加

没有很好的方法来验证属性是否唯一。您将获得的最接近的结果是确保它在创建时是唯一的,然后实现一个自定义的setter方法,该方法将阻止任何更改ID的人。


5
一个更具建设性的答案-您应该被标记为解决方案!
Grouchal

1
生成UUID是最好的方法。我们正在我们的应用程序中使用它,并且效果很好。
object2.0 2013年

46

请记住,Core Data是一个对象图持久性框架,而不是数据库。诸如主键之类的事物被抽象掉了,因为它们取决于持久性存储的实现。


2
这应该是答案@Mugunth应该选择的答案!感谢您的见解。
伦纳德

那么Core Data会自行生成主键吗?
Next Developer

24

Core Data拥有自己的主键-您不必添加一个。您可以使用

NSManagedObjectID *moID = [managedObject objectID];

14

有时在黑客时需要主键的实际整数。这是一个可以抓住它的方法:

NSManagedObjectID *yourManagedObjectID = [yourManagedObject objectID];
int yourManagedObject_PK = [[[[[yourManagedObjectID URIRepresentation] absoluteString] lastPathComponent] substringFromIndex:1] intValue];

尽管CoreData是一个对象图,但是如果查看CoreData生成的SQLite数据库数据,这种获取NSManagedObject主键的方法应该不是问题。ii在相同的代码中一起使用了CoreData和低级sqlite3 C库,并将主键从CoreData传递到sqlite3来获取记录也很好。

!如果您打算在生产中使用此代码,请注意对数据库主键转换为URIRepresentation的方式可能进行的内部更改,这可能会破坏您的代码。

请享用


1
在对象ID和SQLite RID之间未定义任何关系。只能用于特定版本的临时密钥,但对于持久化主密钥则使用错误的方法,因为它可以在其他版本上静默地被破坏。
尼尔2012年

您所说的“在其他版本处中断”到底是什么意思?为什么要更改主键?
manitu 2012年

PK值不会更改,但是可以更改用于表示URL的算法,因为没有正式定义算法。在那种情况下,不能保证您的代码提取有效的PK值。(如果您有任何定义算法的消息源,让我知道,那么我建议您发布)
eonil 2012年

1
好。有时,当黑客攻击的部分令人信服时。我的向下投票目前处于锁定状态,因此您进行一些编辑后,我将删除向下投票。
尼尔2012年

2
为了提高速度和效率,有时最好使用sql。我的示例是一个查询,其中包含count(*),总和,平均值和组。它是一个在OO中做的PAIN,对于SQL是单行的!那个“ hack”工作得很好,如果苹果改变了它,那么他们仍然必须以某种方式使sql join工作,所以我想我们暂时还可以;)。即使理论上我们不应该这样做。在我看来,完全隐藏数据库是错误,而不是真正的技术原因,这更多是由原则驱动的。我们这样做,通过SQL获得批处理。即使有框架,也总是在许多其他系统中。
埃里克·吉格

0

在不管理NSManagedObjectID的情况下,您可以在管理远程数据收集之前对属性进行快速检查。

我做了一个实用方法,在这里检查


0

一个快速扩展来检索主键

extension NSManagedObject {
    var primaryKey : String {
        guard objectID.uriRepresentation().lastPathComponent.count > 1 else { return "" }
        return objectID.uriRepresentation().lastPathComponent.substring(from: 1)
    }
}

对于字符串

extension String
{
    func substring(from : Int) -> String {
        guard self.count > from else { return "" }
        return String(self[self.index(self.startIndex, offsetBy: from)...])
     }
}

-3

我宁愿使用时间+类名称作为唯一标识符。


2
确实不建议这样做,何时可以保证不能同时创建多个对象?
fat32

不推荐也。此方法不能保证密钥是唯一的。
科迪

@Fynh我确实发布了代码,虽然我的帖子可能不完整,但是我一直在同步时间获取方法。
infiniteLoop
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.