CoreData:错误:无法解决乐观锁定失败:乐观锁定失败(null),只有旧记录,为啥?

Posted

技术标签:

【中文标题】CoreData:错误:无法解决乐观锁定失败:乐观锁定失败(null),只有旧记录,为啥?【英文标题】:CoreData: error: failed to resolve optimistic locking failure: optimistic locking failure with (null), Only with old records,why?CoreData:错误:无法解决乐观锁定失败:乐观锁定失败(null),只有旧记录,为什么? 【发布时间】:2015-11-04 10:52:49 【问题描述】:

我有一个实际版本号为 2.4 的应用程序。从 1.0 版本开始,我在每次更新时都使用应用程序委托中的核心数据。因此,每次更新我都在 1.0 版附带的原始数据库中添加了元素。这是添加元素的方式,例如:

 //ADD ELEMENT
if (context == nil)  context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
Negozi *newElement = [NSEntityDescription insertNewObjectForEntityForName:@"Elements" inManagedObjectContext:context];
newElement.name=@"element name";
newElement.id=@"101";
[context save:nil];

1.0 附带的 db 包括从 1 到 100 的 newElement.id ,从 newElement.id 101 是在应用程序的较新版本之一中添加的元素。问题来自于 deleteObject。这样我就可以从我的上下文中删除一个对象:

if (context == nil)  context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
NSError *error=nil;

///DELETE Element with id 101
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Elements" inManagedObjectContext:context];
[fetchRequest setEntity:entity];

NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

NSString *ElementToDelete=[NSString stringWithFormat:@"%@",@"101"];

for (int i=0; i<[fetchedObjects count]; i++) 

    if ([[[fetchedObjects objectAtIndex:i] valueForKey:@"id"] isEqualToString:ElementToDelete]) 

        [contesto deleteObject:[fetchedObjects objectAtIndex:i]];

    


 [contesto save:nil];

使用此代码,我可以成功地从 id 101 中删除对象(随着应用程序的更新添加的对象)。如果我尝试删除一些 id

CoreData: error: failed to resolve optimistic locking failure: optimistic locking failure with (null)

这是我的托管对象上下文代码:

#pragma mark -
#pragma mark Core Data stack


- (NSManagedObjectContext *)managedObjectContext 

if (managedObjectContext_ != nil) 
    return managedObjectContext_;


NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) 
    managedObjectContext_ = [[NSManagedObjectContext alloc] init];
    [managedObjectContext_ setPersistentStoreCoordinator:coordinator];


return managedObjectContext_;




- (NSManagedObjectModel *)managedObjectModel 

if (managedObjectModel_ != nil) 
    return managedObjectModel_;


NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Elements" withExtension:@"momd"];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
return managedObjectModel_;


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 

if (persistentStoreCoordinator_ != nil) 
    return persistentStoreCoordinator_;


NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Elements.sqlite"];

NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent:@"Elements.sqlite"];

NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) 
    NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"Elements" ofType:@"sqlite"];
    if (defaultStorePath) 
        [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
        [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:defaultStorePath]];
    




NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];


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]) 

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
    

return persistentStoreCoordinator_;




为什么我不能删除最初存储在 db 中的对象?

【问题讨论】:

【参考方案1】:

您正在遍历获取结果列表,然后想要修改它(通过删除元素)。这可能会导致您所描述的问题。

相反,清理您的代码并只获取您要删除的元素,而不是所有元素。这消除了循环,也更加高效。

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:"Element"];
request.predicate = [NSPredicate predicateWithFormat:@"id = %@", @(101)];
NSArray *result = [context executeFetchRequest:request error:&fetchError];
if (result.count == 1) 
    NSManagedObject *element = result.firstObject;
    [context deleteObject:element];
    [context save:&saveError];

else  NSLog(@"Element not found."); 

【讨论】:

以上是关于CoreData:错误:无法解决乐观锁定失败:乐观锁定失败(null),只有旧记录,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

由于乐观锁定失败,使用哪个 HTTP 状态代码来拒绝 PUT

如何使用StampedLock乐观锁定?(我无法理解来自java doc的代码示例)

乐观锁定的重试机制(spring data + JPA)

使用 JPA / Hibernate 在无状态应用程序中进行乐观锁定

如何从Java代码编写乐观和悲观锁定

乐观锁定问题-rejectValue 不起作用,无论如何都保存了坏域