我正在实现一个自定义NSIncrementalStore子类,它使用关系数据库进行持久存储.我仍在努力的一件事是支持乐观锁定.
(可以在下面的问题中跳过这个冗长的描述)
我分析了Core Data的SQLite增量存储如何通过检查它生成的SQL日志来解决这个问题,并得出以下结论:
数据库中的每个实体表都有一个Z_OPT列,它指示从1(初始插入)开始修改此实体(行)的特定实例的次数.
每次修改托管对象时,其相应数据库行中的Z_OPT值都会递增.
存储维护NSIncrementalStoreNode实例的缓存(在Core Data docs中称为行缓存),每个实例的版本属性等于由托管对象的行上的先前SELECT或UPDATE SQL查询返回的Z_OPT值.
当从NSManagedObjectContext返回托管对象时(例如,通过对其执行NSFetchRequest),MOC会创建包含此版本号的此对象的快照.
修改或删除对象时,Core Data通过比较缓存的行和对象快照的版本,确保它未在上下文之外被修改或删除.当-save:在对象所属的上下文上调用时,所有这些都会发生.如果版本不同,则基于集合并策略检测并处理合并冲突.
保存MOC时,为每个修改/删除的对象调用-newValuesForObjectWithID:withContext:error:方法,后者又返回带有版本号的NSIncrementalStoreNode.然后将此版本与快照的版本进行比较,如果它们不同,则保存将因适当的合并冲突而失败(至少使用默认合并策略).
这个简单的用例适用于我的商店,因为-newValuesForObjectWithID:withContext:error:首先检查行缓存,如果在其他上下文中使用相同的商店实例同时修改了该对象,那么这就足够了.如果是这种情况,则缓存包含具有更高版本号的更新行,该行足以检测冲突.
但是,我如何检测到底层数据库已经在我的商店外被修改,可能是由使用相同数据库文件的其他应用程序或其他商店实例?我知道这是一个不常见的边缘情况,但Core Data正确处理它,我宁愿做同样的事情.
Core Data的商店使用这些SQL查询来更新/删除对象的行:
UPDATE ZFOO SET Z_OPT=Y, (...) WHERE (...) AND Z_OPT=X
DELETE FROM ZFOO WHERE (...) AND Z_OPT=X
Run Code Online (Sandbox Code Playgroud)
其中:
X - 商店最后知道的版本号(来自缓存)
Y - 新版本号
如果此类查询失败(没有行受影响),则会在商店的缓存中更新该行,并将其版本与先前缓存的版本进行比较.
我的问题是:自定义NSIncrementalStore如何通知Core Data一些更新/删除/锁定的对象发生了乐观锁定失败?这是这是唯一能告诉大家,当它处理店里NSSaveChangesRequest …