Mas*_*aro 6 iphone core-data ipad ios
此代码引发"CoreData:error:(19)PRIMARY KEY必须是唯一的"错误.该Day实体只有一个when属性,它是一个NSDate,而被称为一对多的关系tasks.为什么这个错误?如果Day已经存储了具有特定日期的,我会获取它,否则我会插入它.因此,对于每天的对象,应该有不同的when属性.我不确定这是否是主键.怎么解决这个?先感谢您.
NSMutableSet *occurrences = nil;
occurrences = ...
NSMutableOrderedSet *newSet = [NSMutableOrderedSet orderedSetWithCapacity:[occurrences count]];
for(NSDate *current in occurrences) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// try to find a corresponding Day entity whose when attribute is equal to the current occurrence
// if none is available, create it
Day * day = [[self getDayForDate:current inManagedObjectContext:moc] retain];
if(!day){
day = (Day *) [NSEntityDescription insertNewObjectForEntityForName:@"Day" inManagedObjectContext:moc];
}
day.when = current;
[day addTasksObject:aTask];
[newSet addObject:day];
[moc insertObject:day];
[moc processPendingChanges];
[day release];
[pool release];
}
- (Day *)getDayForDate:(NSDate *)aDate inManagedObjectContext:(NSManagedObjectContext *)moc
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Day" inManagedObjectContext:moc];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(when == %@)", aDate];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
[request release];
Day *theDay = nil;
if(array && [array count] == 1){
theDay = [array objectAtIndex:0];
}
return theDay;
}
Run Code Online (Sandbox Code Playgroud)
blu*_*ary 19
我最近一直在努力解决CoreData: error: (19) PRIMARY KEY must be unique内部iOS应用程序的错误,并且谢天谢地在一两天的研究和代码修改后发现了解决方案,我想在这里分享我的发现,希望它们对我们有所帮助.其他.
首先,一点背景
我们的内部应用程序最初从未构建过任何代码来更新其CoreData存储 - 相反,当需要在应用程序中显示新数据时,每个应用程序构建迭代,CoreData SQLite后备存储文件只是被替换为新版本已使用标准的基于桌面的SQLite编辑器进行编辑 - 即根据需要修改和更新原始SQLite文件.虽然人们认识到这种方法没有考虑到CoreData的"黑盒子"性质,但它实际上在过去的几年中很好地使用了我们的简单应用程序,并且应用程序很高兴地接受了每个更新的SQLite文件.新应用程序构建.
然而,最近我们对应用程序进行了重大改革,从通过Xcode和应用程序重建更新应用程序资产和数据的模型转变为通过Web服务获取新应用程序数据的模型,而这正是在这个新开发过程中这个PRIMARY KEY must be unique问题出现的工作.
经过几天努力解决问题,认为新的CoreData实体创建代码(已经过彻底检查和重新检查)或其他一些相关问题必定存在一些错误,我通过进一步的研究发现我能够使用Xcode为我们的应用程序启用CoreData SQL调试(根据这个非常有用的SO帖子中的说明).
当我仔细研究Xcode中的SQL日志时,我可以看到在每次调用CoreData INSERT对SQLite后备存储的新记录进行调用之前,该框架Z_PRIMARYKEY使用以下查询查询表,SELECT Z_MAX FROM Z_PRIMARYKEY WHERE Z_ENT = ?其中在?后面用相关Z_ENT值替换对于相关的CoreData实体(您可以Z_ENT通过查看Z_PRIMARYKEY表的内容来查看每个CoreData实体的值).这是当我终于明白CoreData的黑盒子里发生了什么的时候!于是我便在使用Mac上的应用丽雅我们的应用程序的SQLite的文件仔细一看,我回顾了内容Z_PRIMARYKEY表,果然Z_MAX列值都设为0.当CoreData首次为我们的应用程序生成空的SQLite后备存储文件时,它们从未从初始值更改!
我立即意识到出现了什么问题以及为什么CoreData报告了主键错误 - 它实际上并没有与任何更高级别的CoreData实体对象的属性相关,而是在最初被怀疑时以某种方式发生冲突,但确实是较低级别的错误.只有现在这个错误才具有绝对意义,它一直存在,它只是在正确的背景下才被理解.
从进一步的研究中可以看出,我们的内部团队在过去几年中成功地直接编辑了SQLite后备存储,插入,更新和删除了各种实体表中的记录,但我们的团队从未做过任何更改在Z_PRIMARYKEY桌面上,由于我们的应用程序以只读方式使用CoreData的方式,这从来就不是问题.
但是,现在我们的应用程序试图创建CoreData条目并将其保存回SQLite后备存储区,INSERT因此生成的许多查询都失败了,因为CoreData无法获取正确的最大主键值任何给定表上的下一个顺序主键,因此INSERT查询将失败,现在可以理解为有意义的PRIMARY KEY must be unique错误!
解决错误
我意识到每个开发人员可能会以各种方式为他们的应用程序生成默认/初始CoreData内容,但是,如果您在CoreData中遇到过这个特定错误并且也很难找到一个立即明确的答案,我希望以下想法有帮助:
我们的应用程序的CoreData后备存储是通过直接编辑SQLite文件(插入,更新和删除实体表中的记录)手动更新的 - 这种方法已经工作了很长时间,因为我们在其中使用了这些数据的只读方式我们的应用.然而,这种方法未能真正识别CoreData的抽象"黑盒子"性质,以及SQLite记录与CoreData实体不等同,并且SQLite连接不等同于CoreData关系,等等.
如果您的应用程序使用任何类型的预先填充的CoreData存储,并且您通过CoreData以外的任何方式填充SQLite后备存储的内容 - 请确保如果您在任何CoreData实体表中创建新记录,您还要确保更新Z_PRIMARYKEY表中的相关记录,将Z_MAX列值设置Z_PK为相关实体表中的当前最大值.
例如,如果您有称为CoreData实体Employee,您的CoreData SQLite的持久性存储备份文件中,这将是一个表格来表示命名ZEMPLOYEE-该表将有一些"隐藏" CoreData列包括Z_PK,Z_ENT,
Z_OPT代表等,除了列你实体的属性和关系.此实体表还将在Z_PRIMARYKEY表中具有相应的记录Z_NAME值Employee- 因此当您将新记录直接添加到ZEMPLOYEE表中时 - 确保在完成添加记录后,您将遍历每个实体表并复制最大值Z_PK值的Z_MAX列到Z_PRIMARYKEY表的列.您输入的值Z_MAX应该是Z_PK相应表中的最大值; 不要设置Z_MAX为等于Z_PK+ 1 的值,因为这不是CoreData所期望的!
您可以Z_PK使用以下SQL 查询任何实体表的最大值:
"SELECT Z_PK FROM ZEMPLOYEE ORDER BY Z_PK DESC LIMIT 1"
Run Code Online (Sandbox Code Playgroud)
这将为您Z_PK提供ZEMPLOYEE表中任何记录的最大值- 显然您应该替换ZEMPLOYEE应用程序数据模型的相关表名.
对于我们的应用程序,我能够编写一个简单的命令行脚本,直接读取SQLite文件,遍历Z_PRIMARYKEY表的每个记录并使用正确的Z_MAX值更新它.完成此操作后,我可以将此更新的文件用作应用程序的持久性存储备份文件.现在,当我插入并保存新的CoreData实体时,一切都按预期工作.
现在我们的应用程序有办法直接通过Web服务请求新数据,我们将完全从手动编辑SQLite后备存储并专门使用CoreData框架更新数据,但有时或其他应用程序,其中可能需要这样快速简便的数据输入,我希望这个答案可以帮助其他开发人员,并节省他们发现这个解决方案所花费的时间和精力.
Day如果你已经拥有它,我想你不需要插入一个新的(当天不是零时就是这种情况).特别是我指的是[moc insertObject:day].
如果使用insertNewObjectForEntityForName,则在保存moc时,该方法会为您插入对象.如果你需要修改它(你已经检索了一个非零日)修改它并保存.另外,我将processPendingChanges在循环结束时执行(仅出于性能原因).
希望有所帮助.
| 归档时间: |
|
| 查看次数: |
5943 次 |
| 最近记录: |