使用validateForInsert防止核心数据重复

时间:2012-12-20 21:20:41

标签: objective-c ios validation core-data duplicates

我的应用程序存在竞争条件,多个API请求可能会返回完全相同的数据并尝试保存它们。我想通过在我的模型上添加validateForInsert来防止这种情况发生。验证的前提只是检查并查看标识符密钥是否已经存在,如此

- (BOOL)validateForInsert:(NSError *__autoreleasing *)error
{
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([CWDeal class])];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"identifier == %@", self.identifier];
    NSError *validateError;
    int count = [[(CWAppDelegate *)[[UIApplication sharedApplication] delegate] privatewriterManagedObjectContext] countForFetchRequest:fetchRequest error:&validateError];
    if (count > 0) {
        return FALSE;
    }
    return [super validateForInsert:error];
}

问题是没有任何东西得救。我有一个managedObjectContext(主线程),它有一个privateWriterManagedObjectContext的父(连接到PSC)。当我导入东西时,我将创建一个importContext(一些后台线程),它具有managedObjectContext的父级。当我获得新数据并尝试保存流程时,就会出现这样的情况。

(记住验证是检查privateWriterMOC对象)

在importContext上创建对象 - >保存 - >验证 - >好的。

(数据被推送到importContext的父级,managedObjectContext)。

保存managedObjectedContext - >验证 - >好。

(数据被推送到managedObjectContext的父级,privateWriterMOC)。

保存privateWriterMOC - >验证 - >失败。 privateWriterMOC识别出对象在其上下文中并且不会保存它们。

似乎没有很多关于使用validateForInsert的文档,所以我希望有人建议如何去做这个?

1 个答案:

答案 0 :(得分:1)

编辑:这是我用

进行制作的代码
- (BOOL)validateForInsert:(NSError *__autoreleasing *)error
{
[[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator] lock];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Deal class])];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"identifier == %@", self.identifier];
NSError *validateError;
int count = [[(AppDelegate *)[[UIApplication sharedApplication] delegate] validationContext] countForFetchRequest:fetchRequest error:&validateError];
if (count > 0) {
    [[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator] unlock];
    return FALSE;
}
[[(CWAppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator] unlock];
return [super validateForInsert:error];
}

锁定PSC是这项工作的关键。在不同的环境试图同时接触PSC之前,我遇到了很多僵局。我用这种方法发现的唯一缺陷是,如果一个对象返回false,则整个上下文被标记为无效并且不会保存。假设你有许多好的对象,但是在未保存的上下文中只有一个坏对象,单个坏对象将不允许保存好对象。我在测试时遇到了这个问题,但在生产中我没有看到任何问题。


当我写这个问题并且刚刚测试时,我将发布一个我想出的答案。我不知道这是否是正确的想法,但它似乎在此时防止重复。

我所做的是在appDelegate中创建另一个名为validationContext的上下文,并将其设置为与privateWriterMOC完全相同。基本上这个想法是它只连接到商店,并且它已知的唯一数据已经被写入。当调用validateForInsert时,我使用validationContext来执行提取,这将通知我该对象是否已被保存。

我相信竞争条件仍然可能发生(假设写入和获取同时发生并且fetch首先返回)但我会更多地研究它(可能sqlite3 db是原子的吗?)。竞争条件是一个非常优秀的案例,但我只是想处理以防万一。