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:&amp;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 约束失败(SQLAlchemy)

SQLError 19 UNIQUE 约束失败

模型 unique_together 约束 + 无 = 失败?

CoreData(IOS)多列的唯一约束?

Django:如何处理CreateView中针对UNIQUE约束的错误消息失败

mysql 中UNIQUE KEY 到底是约束还是索引?