IOS Coredata UNIQUE 约束失败:
Posted
技术标签:
【中文标题】IOS Coredata UNIQUE 约束失败:【英文标题】:IOS Coredata UNIQUE constraint failed: 【发布时间】:2015-10-27 10:41:07 【问题描述】:我正在尝试将数据插入 coredata,但我收到了类似的错误,
CoreData:错误:(1555)唯一约束失败:ZSIDETABLENAME.Z_PK
场景:-
首先:从 appdelegate.m 我将数据从我的 SQL 文件复制到文档目录的 sql 文件。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
if (_persistentStoreCoordinator != nil)
return _persistentStoreCoordinator;
// Create the coordinator and store
NSString* from;
NSString* to;
NSArray* mainPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [mainPath objectAtIndex:0]; // Get documents folder
/*VoiceRecords.plist file*/
from=[[NSBundle mainBundle]pathForResource:@"News" ofType:@"sqlite"];
to=[documentsDirectory stringByAppendingPathComponent:@"News.sqlite"];
[[NSFileManager defaultManager]copyItemAtPath:from
toPath:to error:nil];
from=nil;
to=nil;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"News.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
@NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
return _persistentStoreCoordinator;
它工作正常。然后我试图将用户输入的 url 保存在 mainviewcontroller.m 的 coredata 中。
- (void)feedParserDidFinish:(MWFeedParser *)parser
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"IWorld"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"feedurl = %@", self.Feedlink];
NSManagedObjectContext *context = [self managedObjectContext];
if ([[context executeFetchRequest:fetchRequest error:NULL] count] == 0)
NSError *error = nil;
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"feedurl contains %@",check];
[fetchRequest setPredicate:predicate];
NSMutableArray *checkp = [[context executeFetchRequest:fetchRequest error:&error]mutableCopy];
if (checkp.count<=0)
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"IWorld" inManagedObjectContext:context];
[newDevice setValue:self.Name forKey:@"name"];
[newDevice setValue:self.WebsiteName forKey:@"websitename"];
[newDevice setValue:self.Feedlink forKey:@"feedurl"];
// Save the object to persistent store
if (![context save:&error])
NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
//Save value in lockbox
NSArray *keys = [[[newDevice entity] attributesByName] allKeys];
NSDictionary *dict = [newDevice dictionaryWithValuesForKeys:keys];
NSFetchRequest *fetchrequestforside=[NSFetchRequest fetchRequestWithEntityName:@"Sidetablename"]; //Sidetablename is entity
fetchrequestforside.predicate=[NSPredicate predicateWithFormat:@"feedurl = %@", self.Feedlink];
NSManagedObjectContext *context = [self managedObjectContext];
if ([[context executeFetchRequest:fetchrequestforside error:NULL] count] == 0)
// Create a new managed object
NSError *error = nil;
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"feedurl contains %@",check ]; //check is urlstring
[fetchrequestforside setPredicate:predicate];
NSMutableArray *checkp = [[context executeFetchRequest:fetchrequestforside error:&error]mutableCopy];
if (checkp.count<=0) //if coredata will find url then notstore in coredata else stored procedure
NSManagedObject *newDevice1 = [NSEntityDescription insertNewObjectForEntityForName:@"Sidetablename" inManagedObjectContext:context];
if (self.Name)
[newDevice1 setValue:self.Name forKey:@"name"];
if (self.WebsiteName)
[newDevice1 setValue:self.WebsiteName forKey:@"websitename"];
if (self.Feedlink)
[newDevice1 setValue:self.Feedlink forKey:@"feedurl"];
NSError *error = nil;
if (![context save:&error])
NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]); // Getting error here through nslog //CoreData: error: (1555) UNIQUE constraint failed: ZSIDETABLENAME.Z_PK
注意:这一切都是第一次发生。第二次我将运行应用程序时一切正常。不知道问题出在哪里?
【问题讨论】:
根据错误消息,您已将属性 sidetablename 设置为唯一,并且您正在尝试为属性 sidetablename 保存另一个具有相同值的对象。您是否已通过调试器查看您尝试保存的对象中的内容以及实际核心数据数据库中的内容?您在尝试自我诊断问题时做了什么?这些测试的结果是什么?在调试器中单步执行时您看到了什么? 您是如何创建要复制的 SQLite 文件的? @TomHarrington 先生,我从文档目录中获取了 sql 文件,我在其中输入了静态数据,然后将其复制到包中,然后在应用程序第一次启动时复制数据。 @JodyHagins 是的,先生,我已经用调试器试过了。数据不存储在 sqlfile 中。因为当调试器运行if (![context save:&error])
这种方法时,我在 nslog 中遇到错误。但我可以通过获取请求来获取它。但是当应用程序再次启动时,所有数据都丢失了。
【参考方案1】:
您在 sidetablename 表上遇到主键约束冲突。
因此,我认为您的问题在于您如何创建和复制种子数据库。
很遗憾,您没有提供该信息。因此,我只是猜测你是如何做到的。
我假设您使用 mac 应用程序创建了数据库,或者您是在 ios 模拟器中创建的。然后,您将 sqlite 文件从创建位置复制到捆绑资源中。
由于自 iOS/OSX 7/10.9 以来 WAL 一直是默认模式,我假设您在 WAL 模式下创建了种子数据库。这意味着您可能错过了 -wal 和 -shm 文件。如果您指定任何数据属性都应使用外部存储,那么您也错过了该数据。
在创建要复制的种子数据库时,还需要复制 -shm/wal 文件,或者需要以回滚日志模式创建数据库,该文件中将包含所有添加的数据。
您可以通过在添加持久性存储时设置以下选项来做到这一点(如果您已经使用选项,只需将此选项与其他选项合并)。
NSDictionary *options = @NSSQLitePragmasOption:@@"journal_mode":@"DELETE";
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error])
// Handle error
这是您在创建要复制到捆绑包的数据库时添加持久存储的方式。它将确保所有内容都在实际的数据库文件中。
现在,在您运行代码创建种子文件后,您应该转到该目录并查看周围是否还有其他文件。最好的方法是在终端中。转到该目录并执行“ls -lat”,它将列出按时间排序的所有文件。
警告:SQLite 和 Core Data 都可以创建与 sqlite 文件一起使用的额外文件,具体取决于两个实体的配置。因此,一般来说,您应该将每个核心数据持久存储视为一个文件包。换句话说,您应该为核心数据存储创建一个单独的目录。这样,当 SQLite 或核心数据决定创建额外文件时,所有内容都被限制在一个目录中。
当您将文件复制到您创建种子数据库的捆绑资源中时,您需要确保复制所有内容。
同样,您应该在部署时将包中的所有内容复制到设备。
但是,您应该考虑NSPersistentStoreCoordinator
上的这些方法,而不是使用文件系统...
/* Used for save as - performance may vary depending on the type of old and
new store; the old store is usually removed from the coordinator by the
migration operation, and therefore is no longer a useful reference after
invoking this method
*/
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store
toURL:(NSURL *)URL
options:(nullable NSDictionary *)options
withType:(NSString *)storeType
error:(NSError **)error;
/* copy or overwrite the target persistent store in accordance with the store
class's requirements. It is important to pass similar options as
addPersistentStoreWithType: ... SQLite stores will honor file locks, journal
files, journaling modes, and other intricacies. Other stores will default
to using NSFileManager.
*/
- (BOOL)replacePersistentStoreAtURL:(NSURL *)destinationURL
destinationOptions:(nullable NSDictionary *)destinationOptions
withPersistentStoreFromURL:(NSURL *)sourceURL
sourceOptions:(nullable NSDictionary *)sourceOptions
storeType:(NSString *)storeType
error:(NSError**)error NS_AVAILABLE(10_11, 9_0);
因此,我相信,如果您正确地创建数据库,然后将其完全正确地复制到资源包和应用程序中,那么您的问题就会消失。
【讨论】:
真是个猜测!对,先生。你真的很棒,先生。谢谢你,先生。非常感谢。 我正在使用 CoreData,创建数据库是 ios 自己在做的事情。我有时会收到此错误“CoreData:错误:(1555)唯一约束失败:”。你能帮我吗,我不明白你是怎么解决这个问题的? 我正在将 sqlite-shm 和 sqlite-wam 文件从 Boundle 复制到 Documents 文件夹,但 UNIQUE 错误仍然存在。有什么建议吗? 我删除了我的应用程序并再次运行该项目,它对我来说没有任何问题。谢谢【参考方案2】:当我在后台线程上创建/更新 coredata 实体时出现此错误,在主线程上执行相同操作解决了问题。
【讨论】:
以上是关于IOS Coredata UNIQUE 约束失败:的主要内容,如果未能解决你的问题,请参考以下文章
模型 unique_together 约束 + 无 = 失败?