从Core Data中的关系中删除对象的正确方法

时间:2014-06-17 13:55:49

标签: ios core-data nsmanagedobjectcontext

我有一个简单的数据模型,包含两个实体:Person和Company。可以将一个人分配给许多公司,并且可以将公司分配给许多人。我已经将1家公司和2名员工填入数据库,并将所有人员分配到公司。在填充数据库的过程中,Core Data生成以下日志:

CoreData: sql: INSERT INTO ZCOMPANY(Z_PK, Z_ENT, Z_OPT, ZNAME) VALUES(?, ?, ?, ?)
CoreData: sql: INSERT OR REPLACE INTO Z_1PERSONS(Z_1COMPANIES, Z_2PERSONS) VALUES (1, 2)
CoreData: sql: INSERT OR REPLACE INTO Z_1PERSONS(Z_1COMPANIES, Z_2PERSONS) VALUES (1, 1)
CoreData: sql: INSERT INTO ZPERSON(Z_PK, Z_ENT, Z_OPT, ZNAME) VALUES(?, ?, ?, ?)
CoreData: sql: INSERT INTO ZPERSON(Z_PK, Z_ENT, Z_OPT, ZNAME) VALUES(?, ?, ?, ?)

接下来,我关闭应用程序,再次启动它并删除该公司。核心数据然后执行以下操作:

CoreData: sql: SELECT 0, t0.Z_PK FROM Z_1PERSONS t1 JOIN ZPERSON t0 ON t0.Z_PK = t1.Z_2PERSONS WHERE t1.Z_1COMPANIES = ? 
CoreData: annotation: sql connection fetch time: 0.0009s
CoreData: annotation: total fetch execution time: 0.0018s for 2 rows.
CoreData: annotation: to-many relationship fault "persons" for objectID 0x8d281e0 <x-coredata://0AFFC353-8C34-43AD-8D30-4483FB44BEA4/Company/p1> fulfilled from database.
Got 2 rows
CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME FROM ZPERSON t0 WHERE  t0.Z_PK = ? 
CoreData: annotation: sql connection fetch time: 0.0008s
CoreData: annotation: total fetch execution time: 0.0016s for 1 rows.
CoreData: annotation: fault fulfilled from database for : 0x8e19940 <x-coredata://0AFFC353-8C34-43AD-8D30-4483FB44BEA4/Person/p1>
CoreData: sql: SELECT 0, t0.Z_PK FROM Z_1PERSONS t1 JOIN ZCOMPANY t0 ON t0.Z_PK = t1.Z_1COMPANIES WHERE t1.Z_2PERSONS = ? 
CoreData: annotation: sql connection fetch time: 0.0009s
CoreData: annotation: total fetch execution time: 0.0022s for 1 rows.
CoreData: annotation: to-many relationship fault "companies" for objectID 0x8e19940 <x-coredata://0AFFC353-8C34-43AD-8D30-4483FB44BEA4/Person/p1> fulfilled from database.
Got 1 rows
CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME FROM ZPERSON t0 WHERE  t0.Z_PK = ? 
CoreData: annotation: sql connection fetch time: 0.0006s
CoreData: annotation: total fetch execution time: 0.0014s for 1 rows.
CoreData: annotation: fault fulfilled from database for : 0x8e18f90 <x-coredata://0AFFC353-8C34-43AD-8D30-4483FB44BEA4/Person/p2>
CoreData: sql: SELECT 0, t0.Z_PK FROM Z_1PERSONS t1 JOIN ZCOMPANY t0 ON t0.Z_PK = t1.Z_1COMPANIES WHERE t1.Z_2PERSONS = ? 
CoreData: annotation: sql connection fetch time: 0.0006s
CoreData: annotation: total fetch execution time: 0.0015s for 1 rows.
CoreData: annotation: to-many relationship fault "companies" for objectID 0x8e18f90 <x-coredata://0AFFC353-8C34-43AD-8D30-4483FB44BEA4/Person/p2> fulfilled from database.
Got 1 rows
CoreData: sql: BEGIN EXCLUSIVE
CoreData: sql: DELETE FROM ZCOMPANY WHERE Z_PK = ? AND Z_OPT = ?
CoreData: sql: DELETE FROM Z_1PERSONS WHERE Z_1COMPANIES = 1
CoreData: sql: UPDATE ZPERSON SET Z_OPT = ?  WHERE Z_PK = ? AND Z_OPT = ?
CoreData: sql: UPDATE ZPERSON SET Z_OPT = ?  WHERE Z_PK = ? AND Z_OPT = ?
CoreData: sql: COMMIT

我们看到Core Data从数据库中获取所有分配给已删除公司的人员。接下来,它为每个人提取公司集合。最终预期的删除操作将在数据库上执行:

DELETE FROM ZCOMPANY WHERE Z_PK = ? AND Z_OPT = ?
DELETE FROM Z_1PERSONS WHERE Z_1COMPANIES = 1

当我删除公司时,一个managedObjectContext是清除的(没有在其中注册的对象),因此没有理由清除内存中的无效关系,因为内存中没有对象。应该做的唯一事情是上面列出的数据库级删除操作。

情况是一个问题,因为当我有1000人被分配到公司时,删除公司的操作需要花费太多时间(以秒计算)。

删除只执行必要操作并确保数据一致性的公司的正确方法是什么?

在这里,您可以下载为当前问题准备的Xcode项目: Xcode project

2 个答案:

答案 0 :(得分:2)

核心数据不是数据库。核心数据是可以持久保存到数据库的对象层次结构。

在这种情况下,这是一个重要的区别。删除某些内容时,Core Data将检索关系两侧的对象,以确保保留参照完整性。使用SQLite,这似乎效率低下(而且确实如此)。当商店是别的东西时,需要进行双重检查。

那么,如何解决这个问题呢?一种是承认删除需要一些时间并启动后台私有队列来处理删除。不是最佳的。

另一种选择是在这两个表之间使用软引用。再次不理想。

如果您可以等到iOS 8,您可以进行批量更新以取消关系。

答案 1 :(得分:0)

CoreData性能问题的常见解决方法是在后台线程中进行耗时的处理。 幸运的是,这不是一件容易的事,CoreData不是线程安全的。

使用MagicalRecord等第三方组件可以提供帮助,look at this document了解有关如何“保存在后台线程中”的详细信息。