gpt4 book ai didi

ios - CoreData managedObjectContext save 违反了 Z_PK 的 UNIQUE 约束

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:58:57 25 4
gpt4 key购买 nike

我在 iOS 应用程序中使用 CoreData 来管理学习新语言的“闪存卡”应用程序中的单词。

我遇到的问题是,当我为新实体设置数据并尝试将其保存到数据存储时,我违反了对 sqlite 数据库的 UNIQUE CONSTRAINT 要求。有问题的列是 Z_PK 列,据我所知,它是最初创建数据存储时由 iOS 核心数据方法创建的主键。

这是我尝试保存时收到的 UNIQUE CONSTRAINT 消息:

2015-03-14 09:25:14.427 ghoti[25856:1107373] CoreData: error: (1555) UNIQUE constraint failed: ZGHOTIENTITY.Z_PK (lldb)

Z 是所有这些 SQL 列上的前缀
GHOTIENTITY 是我的数据存储
Z_PK为主键

这是 firefox 中 sqlite“编辑器”中数据表的快速截图: datastructure from sqlite

业务对象实体本身的定义不包括Z_PK列:

@implementation ghotiEntity

@dynamic numberCorrect;
@dynamic numberIncorrect;
@dynamic likelihoodOfPresentingWord;
@dynamic englishText;
@dynamic hebrewText;
@dynamic phoneticText;

@end

如果只是将 ghotiEntity.Z_PK 设置为数据存储区中 Z_PK 的最大值 + 1 这么简单,我会很生气 - 但顺从 - 但该列甚至不是第一个实体定义的一部分地方。


编辑 - 一位乐于助人的用户要求提供代码,所以我将其添加到此处而不是试图将其塞入评论中:

我正在使用我在网络上看到的核心数据方法的 mmBusinessObject 集合。 Kevin McNeish 对其进行了全面解释 here .

基本结构是这样的:

mmBusinessObject.m 和 .h 很好地将 managedObject 方法包装成“易于阅读和处理”的东西。为了便于阅读,我在此处复制了两个元素 [entity createEntities] 和 [entity saveEntities] 的片段,并在本文末尾复制了完整的 .m 文件。 (请注意,我还没有内置所有的错误检查,我只是想让基本功能正常工作。

创建一个新实体:

// Creates a new entity of the default type and adds it to the managed object context
- (NSManagedObject *)createEntity
{
return [NSEntityDescription insertNewObjectForEntityForName:self.entityClassName inManagedObjectContext:[self managedObjectContext]];
}

保存更改

- (void)saveEntities
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&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.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}

所以我的操作代码(在我的 ViewController.m 文件中)是这样做的:(注意 ghotiEntity 是我的特定业务对象。

- (IBAction)saveButtonAction:(UIButton *)sender {

ghotiEntity *newGhotiEntry = (ghotiEntity *)[ghotiData createEntity];
newGhotiEntry.englishText=self.englishWord.text;
newGhotiEntry.hebrewText=self.hebrewWord.text;
newGhotiEntry.phoneticText=self.phoneticWord.text;
newGhotiEntry.numberCorrect=0;
newGhotiEntry.numberIncorrect=0;
newGhotiEntry.likelihoodOfPresentingWord=0;

[ghotiData saveEntities];

[self enableRegularUI];
[self pickNextCard];
}

从上面的 saveEntities 方法中的 NSLog 行,我得到了诊断信息,它是 Z_PK 列有 UNIQUE CONSTRAINT 问题。


正如上面所 promise 的,这里是完整的 .m 文件。我需要确保清楚地表明,这段代码的功劳归功于上面提到的 Kevin McNeish,或者在其他地方发布了相同代码的其他几个合作者中的任何一个……只需在谷歌中搜索 mmBusinessObject。我觉得Kevin是鼻祖,他的教程真的很好。我看到的版本的前几行都有凯文的名字!

#import "mmBusinessObject.h"

@implementation mmBusinessObject

// Initialization
- (id)init
{
if ((self = [super init])) {
_copyDatabaseIfNotPresent = YES;
}
return self;
}

// Creates a new entity of the default type and adds it to the managed object context
- (NSManagedObject *)createEntity
{
return [NSEntityDescription insertNewObjectForEntityForName:self.entityClassName inManagedObjectContext:[self managedObjectContext]];
}

// Delete the specified entity
- (void) deleteEntity:(NSManagedObject *)entity {
[self.managedObjectContext deleteObject:entity];
}

// Gets entities for the specified request
- (NSMutableArray *)getEntities: (NSString *)entityName sortedBy:(NSSortDescriptor *)sortDescriptor matchingPredicate:(NSPredicate *)predicate
{
NSError *error = nil;

// Create the request object
NSFetchRequest *request = [[NSFetchRequest alloc] init];

// Set the entity type to be fetched
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];

// Set the predicate if specified
if (predicate) {
[request setPredicate:predicate];
}

// Set the sort descriptor if specified
if (sortDescriptor) {
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
}

// Execute the fetch
NSMutableArray *mutableFetchResults = [[_managedObjectContext executeFetchRequest:request error:&error] mutableCopy];

if (mutableFetchResults == nil) {

// Handle the error.
}

return mutableFetchResults;
}

// Gets all entities of the default type
- (NSMutableArray *)getAllEntities
{
return [self getEntities:self.entityClassName sortedBy:nil matchingPredicate:nil];
}

// Gets entities of the default type matching the predicate
- (NSMutableArray *)getEntitiesMatchingPredicate: (NSPredicate *)predicate
{
return [self getEntities:self.entityClassName sortedBy:nil matchingPredicate:predicate];
}

// Gets entities of the default type matching the predicate string
- (NSMutableArray *)getEntitiesMatchingPredicateString: (NSString *)predicateString, ...;
{
va_list variadicArguments;
va_start(variadicArguments, predicateString);
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString
arguments:variadicArguments];
va_end(variadicArguments);
return [self getEntities:self.entityClassName sortedBy:nil matchingPredicate:predicate];
}

// Get entities of the default type sorted by descriptor matching the predicate
- (NSMutableArray *)getEntitiesSortedBy: (NSSortDescriptor *) sortDescriptor
matchingPredicate:(NSPredicate *)predicate
{
return [self getEntities:self.entityClassName sortedBy:sortDescriptor matchingPredicate:predicate];
}

// Gets entities of the specified type sorted by descriptor, and matching the predicate string
- (NSMutableArray *)getEntities: (NSString *)entityName
sortedBy:(NSSortDescriptor *)sortDescriptor
matchingPredicateString:(NSString *)predicateString, ...;
{
va_list variadicArguments;
va_start(variadicArguments, predicateString);
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString
arguments:variadicArguments];
va_end(variadicArguments);
return [self getEntities:entityName sortedBy:sortDescriptor matchingPredicate:predicate];
}

- (void) registerRelatedObject:(mmBusinessObject *)controllerObject
{
controllerObject.managedObjectContext = self.managedObjectContext;
}

// Saves all changes (insert, update, delete) of entities
- (void)saveEntities
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&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.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}

#pragma mark -
#pragma mark Core Data stack

/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext {

if (_managedObjectContext != nil) {
return _managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}

/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {

if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:self.dbName withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}

/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}

// If the sqlite database doesn't already exist, create it
// by copying the sqlite database included in this project

if (self.copyDatabaseIfNotPresent) {

// Get the documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *docsDir = paths[0];

// Append the name of the database to get the full path
NSString *dbcPath = [docsDir stringByAppendingPathComponent:
[self.dbName stringByAppendingString:@".sqlite"]];

// Create database if it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:dbcPath]) {
NSString *defaultStorePath = [[NSBundle mainBundle]
pathForResource:self.dbName ofType:@"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:dbcPath error:NULL];
}
}



}

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:
[NSString stringWithFormat:@"%@%@", self.dbName, @".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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.

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:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

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(@"%@",storeURL);
if ([error code] == 134100) {
[self performAutomaticLightweightMigration];
}
else
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
return _persistentStoreCoordinator;
}

- (void)performAutomaticLightweightMigration {

NSError *error;

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@%@", self.dbName, @".sqlite"]];

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error]){
// Handle the error.
}
}


#pragma mark -
#pragma mark Application's Documents directory

/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

@end

最佳答案

我在 Z_PK 约束问题上遇到了同样的问题。这是因为我从我的应用程序的文档文件夹中复制了空的 sqlite 数据库,并使用 Firefox 的 SQLite 管理器加载项预填充了它。我忘记的步骤是更新 Z_PrimaryKey 表...您必须更新每个表的 Z_MAX 值,以便 Core Data 知道在将新记录添加到数据库时要使用的下一个 Z_PK。只需将每个 Z_Max 值设置为每个表中的记录数。保存它并将其放回您的应用中,一切都会好起来的。

关于ios - CoreData managedObjectContext save 违反了 Z_PK 的 UNIQUE 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29050185/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com