核心数据故障和多对多关系的获取
我对核心数据行为有几个“理论”问题,这些问题涉及到多对关系会发生什么、何时依赖从父实体遍历关系以及何时应构建新的获取请求。它们都非常相关。
背景
假设有一个父实体RPBook
,它与RPChapter
具有一对多关系。一本书有很多章节。核心数据模型中也设置了逆矩阵。涉及手动排序关系的基本形式,因此 RPChapter
实体具有 chapterIndex
属性。我在这里没有使用 iOS5 新的有序关系(也与这些问题无关)。
要访问书中的章节,可以使用 chapters
关系访问器:
RPBook *myBook; // Assume this is already set to an existing RPBook
NSSet *myChapters = myBook.chapters
使用/设置
在 iPhone 应用程序中,我们从显示 RPBook< 列表的表格视图开始/code> 实例。相应的章节不会作为支持表视图的获取结果控制器的获取规范的一部分进行预获取,因为还不需要这些章节。
我现在选择其中一个 RPBook 实例,我被带到一个新页面,并且我的视图控制器中有这个 RPBook 实例引用,它没有它的 章节
已预取。
问题 1:立即在 chapters
关系上调用 filteredSetUsingPredicate:
如果我想使用 filteredSetUsingPredicate:
通过 chapters
关系进行过滤> 直接,考虑到我没有预取我正在查看的当前 RPBook
的所有相关 RPChapter
实例,这是否可以可靠地工作?换句话说,filteredSetUsingPredicate:
是否会在该关系中的所有对象的幕后触发故障以完成其任务,或者它是否会误导性地仅根据已经发生的章节给出结果在内存中(如果有的话)?
如果我没有大量与一本书相关的章节,我是否应该首先通过调用 allObjects
来设置样式?即
[[self.chapters allObjects] filteredArrayUsingPredicate:predicate]
而不是仅仅:
[self.chapters filteredSetUsingPredicate:predicate]
问题2:批量检索一本书的所有章节
如果我有一个RPBook
实例,但没有预取与其相关的RPChapter
实例,如何我是否强制使用 chapters
关系一次获取一本书的所有章节? [myBook.chapters allObjects]
是否会这样做,或者我仍然可以从该调用中返回错误吗?
我希望 Core Data 能够批量解决所有错误,而不是为奇怪的 RPChapter 询问是否会影响在 上使用
关系,如上面的问题 1 所示。filteredSetUsingPredicate:
的行为而触发错误>chapters
我必须诉诸显式获取请求才能执行此操作吗?我是否应该重新获取已有的 RPBook
,但这一次,在获取请求中请求所有关联的章节也使用 setRelationshipKeyPathsForPrefetching:
获取?
最后一个选项对我来说似乎很浪费,因为我已经有了一个范围关系,它在概念上代表了我感兴趣的所有 RPChapter 实例的子集。我会尽可能地”我只想遍历对象图。
问题 3:同一线程上 RPChapter 实例的 NSFetchedResultsController
Setup 在本例中,我有一个 RPBook 实例,但没有与其相关的预取 RPChapter 实例(但它们确实存在于 Store 中)。在同一个视图控制器中,我还有一个 NSFetchedResultsController (FRC)
,其范围为同一本书的 RPChapter
实例。所以这是相同的线程,相同的托管对象上下文。
FRC 中的 RPChapter 实例与我从 myBook.chapters 中检索的 RPChapter 实例对应的内存中的对象是否相同?相同的ObjectID
?换句话说,运行时是否曾经使用不同物理对象来满足同一线程中同一MOC对相同ObjectID
的托管对象请求在记忆中?
问题 4:在托管对象内安装 NSFetchedResultsController
来为关系查询提供服务的设计模式
我正在尝试决定是否应该能够为内容经常更改的关系的查询提供服务(章节在我的示例中的一本书中)通过使用我的自定义 RPChapter
托管对象子类中提供的内置 chapters
关系,或者如果从设计/架构的角度来看可以的话,安装RPChapter
实例的 FRC
到 RPBook
托管对象类上,以有效地服务有关该书中章节的查询。
如果我可以只依赖 myBook
实例中的 chapters
访问器,那么显然会更干净,但在大量数据的情况下,这里的 FRC 实际上可能会更高效、更高效。存在对多关系中的目标实体。
这是过度杀伤还是这是合理使用 FRC
来以不同方式查询 RPBook
的章节?不知怎的,感觉我错过了简单地遍历对象图的机会。我希望能够相信,当我加载 RPBook
实例时,chapters
关系始终是最新的。
I have several "theory" questions on Core Data behavior related to what happens with a to-many relationship and when to rely on walking the relation from a parent entity and when a fresh fetch request should be built. They're all very much related.
Background
Assume a parent entity RPBook
, which has a to-many relation to RPChapter
. A book has many chapters. The inverse is set in the core data model too. A basic form of manually ordered relationships is involved, so the RPChapter
entity has a chapterIndex
property. I am not using iOS5's new ordered relationships here (not as relevant to these questions either).
To get to the chapters in a book, one would use the chapters
relationship accessor:
RPBook *myBook; // Assume this is already set to an existing RPBook
NSSet *myChapters = myBook.chapters
Usage / Setup
In an iPhone app, we'd start off with a table view showing a list of RPBook
instances. The corresponding chapters wouldn't be pre-fetched as part of the fetch spec for the fetched results controller backing the table view, since those chapters are not yet needed.
I now select one of those RPBook
instances, I'm taken to a new page and I have this RPBook
instance reference in my view controller, which does NOT have its chapters
prefetched.
Question 1: Invoking filteredSetUsingPredicate:
on chapters
relation right away
If I want to filter via the chapters
relation using filteredSetUsingPredicate:
directly, will that even work reliably, given that I didn't pre-fetch all related RPChapter
instances of the current RPBook
I'm looking at? Put another way, does filteredSetUsingPredicate:
trigger faulting behind the scenes of all objects in that relation in order to do its thing, or will it misleadingly only give me results based on which of the chapters already happened to be in memory (if any)?
If I don't have an egregious number of associated chapters to a book, should I instead style this by invoking allObjects
first? i.e.
[[self.chapters allObjects] filteredArrayUsingPredicate:predicate]
instead of just:
[self.chapters filteredSetUsingPredicate:predicate]
Question 2: Batch retrieval of all a book's chapters
In the case I have an RPBook
instance, but no pre-fetched RPChapter
instances related to it, how do I force all of a book's chapters to be fetched in one shot using the chapters
relation? Does [myBook.chapters allObjects]
do that or can I still get faults back from that call?
I want Core Data to fulfill all the faults in a batch instead of tripping faults for the odd RPChapter
asked for if that will affect the behavior of using filteredSetUsingPredicate:
on the chapters
relation, as per Question 1 above.
Must I resort to an explicit fetch request to do this? Should I refetch the RPBook
I already have, but this time, request in the fetch request, that all associated chapters also be fetched using setRelationshipKeyPathsForPrefetching:
?
This last option just seems wasteful to me, b/c I already have a scope relation representing conceptually the subset of all RPChapter
instances I'd be interested in. As much as possible, I'd like to just walk the object graph.
Question 3: NSFetchedResultsController of RPChapter instances on the same Thread
Setup
In this case I have an RPBook
instance, but no pre-fetched RPChapter
instances related to it (but they do exist in the Store). In the same view controller, I also have an NSFetchedResultsController (FRC)
of RPChapter
instances scoped to the very same book. So that's same thread, same managed object context.
Is an RPChapter
instance from the FRC going to be the same object in memory as an RPChapter
instance counterpart I retrieve from myBook.chapters
, that shares the same ObjectID
? Put another way, does the runtime ever fulfill managed object requests for the same ObjectID
from the same MOC in the same Thread, using different physical objects in memory?
Question 4: Design pattern of installing an NSFetchedResultsController
inside a Managed Object to serve queries for a relation
I'm trying to decide whether I should be able to service queries about a relationship whose contents are frequently changing (chapters in a book in my example) by using the built in chapters
relation provided in my custom RPChapter
managed object subclass, or if it's ever okay from a design/architecture perspective, to install an FRC
of RPChapter
instances onto the RPBook
managed object class, to service queries efficiently about chapters in that book.
It's clearly cleaner if I could just rely on the chapters
accessor in myBook
instance, but it seems an FRC here might actually be more performant and efficient in situations where a large volume of destination entities in the to-many relation exist.
Is this overkill or is this a fair use of an FRC
for querying an RPBook
about its chapters in different ways? Somehow it feels like I'm missing the opportunity to walk the object graph simply. I'd like to be able to trust that the chapters
relation is always up to date when I load my RPBook
instance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题 1
是的,它会起作用。当您调用
[book Chapters]
时,该集合将自动填充。当您过滤这些对象时,它们会出错。但是,您应该在此处使用 NSFetchedResultsController ,其谓词类似于@“book == %@”,而不是抓取数组。
问题 2
强制
NSManagedObjectContext
加载所有章节的最佳方法是执行NSFetchRequest
并配置NSFetchRequest
返回完全实现的内容对象而不是错误。这将一次性将它们全部预加载。然而,除非你有大量的章节,否则你不会在这里节省很多。为什么?
因为当您请求这些章节时,即使在故障状态下,Core Data 也会将数据加载到缓存中(不包括二进制数据等一些边缘情况),这样当您“故障”一个对象时,它只是在其中移动的指针内存并且没有额外的磁盘命中。
您可能需要阅读数千章才能看到预取的好处。
问题3
是的。它们将是同一个对象。从同一个
NSManagedObjectContext
检索时,NSManagedObject
实例将始终被共享。这是NSManagedObjectContext
工作的一部分。问题 4
您想要使用
NSFetchedResultsControler
这就是它的工作。手动管理这些东西是浪费的,而且几乎肯定比 Core Data 的实现效率低。但是,关系将始终是最新的,除非您从另一个线程对其进行调整。因此,如果您不期望更新,那么您可以只使用数组。我不会。
Question 1
Yes it will work. When you call
[book chapters]
the set will get populated automatically. When you filter on those objects they will fault in.However, you should be using a
NSFetchedResultsController
here with the predicate being something like @"book == %@" instead of grabbing the array.Question 2
The best way to force the
NSManagedObjectContext
to load all of the chapters would be to do aNSFetchRequest
and configure theNSFetchRequest
to return fully realized objects instead of faults. This will pre-load them all in one go. However, unless you have a TON of chapters, you are not going to get a lot of savings here.Why?
Because when you request those chapters, even in a faulted state, Core Data is going to load the data into a cache (excluding a few edge cases like binary data) so that when you "fault" an object it is just pointers moving around in memory and no additional disk hit.
You would need, probably, thousands of chapters to see any benefit out of a pre-fetch.
Question 3
Yes. They will be the same object.
NSManagedObject
instances will always be shared when retrieved from the sameNSManagedObjectContext
. That is part of the job of theNSManagedObjectContext
Question 4
You want to use a
NSFetchedResultsControler
that is its job. Managing that stuff manually is wasteful and almost guaranteed to be less efficient than Core Data's implementation.However, the relationship will always be up to date unless you are tweaking it from another thread. So if you do not expect updates then you could just use an array. I wouldn't.