如何使用带有插入/删除的 Core Data(或 SQL)维护有序表?

Posted

技术标签:

【中文标题】如何使用带有插入/删除的 Core Data(或 SQL)维护有序表?【英文标题】:How to maintain an ordered table with Core Data (or SQL) with insertions/deletions? 【发布时间】:2011-04-08 08:37:22 【问题描述】:

这个问题是在 Core Data 的上下文中,但如果我没记错的话,它同样适用于更一般的 SQL 案例。

我想使用 Core Data 维护一个有序表,用户可以:

重新排序行 在任何地方插入新行 删除任何现有行

最好的数据模型是什么?我可以看到两种方式:

1) 将其建模为数组:我将一个 int position 属性添加到我的实体

2) 将其建模为链表:我添加了两个一对一关系,nextprevious 从我的实体到自身

1) 使排序变得容易,但插入或删除很痛苦,因为您必须更新其后所有对象的 position

2) 使插入或删除变得容易,但排序非常困难。事实上,我认为我不知道如何表达这种情况下的排序描述符(SQL ORDER BY 子句)。

现在我可以想象 1) 的变体:

3) 向实体添加一个 int ordering 属性,但不是让它一个一个计数,而是让它计数 100 乘 100(例如)。然后插入就像在前一个和下一个现有对象的顺序之间找到任何数字一样简单。只有当 100 个孔被填满时,才需要进行昂贵的重新编号。将该属性设为 float 而不是 int 会更好:几乎总是可以在两个浮点数的中间找到一个新的浮点数。

我在解决方案 3) 的正确轨道上,还是有更聪明的方法?

【问题讨论】:

【参考方案1】:

如果排序是任意的,即不是被建模的数据所固有的,那么您别无选择,只能添加属性或关系来维护顺序。

我建议使用链表,因为它最容易维护。我不确定您所说的链表难以排序是什么意思,因为无论如何您都不太可能不会按任意顺序进行排序。相反,您只需获取最顶层的实例并一路向下走。

按可整除的浮点属性排序是个好主意。您可以创建几乎无限数量的中间索引,只需从较高的现有索引中减去较低的现有索引,将结果除以 2,然后将该结果添加到较低的索引。

如果您需要对表格等进行排序,您还可以将可分索引与链表结合使用。链表可以很容易地找到现有的索引,而可分割的索引可以让你在需要时轻松排序。

Core Data 反对这种排序,因为它通常是不必要的。除非有必要模拟模型描述的真实世界对象、事件或条件,否则您不希望向数据模型添加某些内容。通常,排序/排序不是模型固有的,而只是 UI/视图需要。在这种情况下,您应该在模型和视图之间的控制器中具有排序逻辑。

当您可能不需要时,在将订单添加到模型之前请仔细考虑。

【讨论】:

如果使用链表,您将如何设置 Core Data 排序描述符?使用 Core Data(即NSFetchedResultController)的一点是,如果您提供排序描述符,它将以正确的顺序向您提供查询结果。 排序顺序是数据固有的,仅由用户决定。例如,您想让用户决定他希望她的书按什么顺序放在她的书架上。她可能决定将一本书从位置 7 移动到位置 14 和 15 之间。或者出售位置 12 的书,或者购买新书并将其插入位置 3。第二天,她将决定移动那本书到架子的尽头。使用UITableView 可以轻松实现此操作的 UI。我的问题是这种“偏好值”的最佳表示,以使交换/插入/删除变得足够容易和快速。 我要提醒你,过早的优化是万恶之源。除非您已经测试并发现它效率低下,否则不要花费大量时间来调整排序。在普通的 Core Data 应用程序中,除非您有数千个复杂实体,否则您不会看到任何性能问题。除非您知道您将拥有大量数据,否则请选择最容易实施和维护的系统。 是的,我想优化我作为程序员的时间。从这个角度来看,浮动整除索引方法似乎是最轻量级的。 请注意,所有索引系统都必须定期维护。在某些时候,即使使用浮动系统,您也需要重新索引所有内容。如果您只是不理会索引,它最终会饱和并丢失索引。【参考方案2】:

ios 5 开始,您可以(并且应该)使用 NSOrderedSet 及其可变子类。 →Core Data Release Notes for OS X v10.7 and iOS 5.0

在How can I preserve an ordered list in Core Data查看接受的答案。

【讨论】:

是的。你挖出了一个老问题,你是对的:-)。尽管 NSOrderedSet(例如,它的 API 不如 NSArray 完整)和有序关系(我认为获取的结果控制器不完全支持)存在一些问题。 是的,我尝试让 NSFetchedResultsController 使用有序关系。大多数情况下都成功了——但未能智能地更新表格视图,即动画插入或删除,而不是仅仅做[tableView reloadData]...所以最后我放弃了获取结果控制器,只是预取了整个列表:- /

以上是关于如何使用带有插入/删除的 Core Data(或 SQL)维护有序表?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Core Data 陡峭学习曲线的 RestKit 0.10.1

Core Data 无法删除从未插入的对象错误

是否有用于在 Core Data DB 中插入/编辑行的编辑器?

Core Data,我如何有效地查找和删除托管对象

如何删除 Core Data 存储中除一个对象之外的所有对象?

Core Data + iCloud,更改通知插入和删除关系中的对象但不更新关系中现有实体的属性