0

What is the best / most efficient way to access core data children in a multilevel one-to-many model?

I have a model with Board > List > Card > ..., always in a one-to-many relation. At the start view all Boards are fetched.

Let's say we are in the SingleListView, looking at all cards from one List, that has been passed in. Now I can either directly use the Core Data class accessor from the list (NSSet transformed to Array):

@ObservedObject var list: ListEntity
...
ForEach(list.cardsArray) {
    ....

or I can fetch the cards with predicate

@FetchRequest
private var cards: FetchedResults<CardEntity>

init(list: ListEntity) {
    _cards = FetchRequest<CardEntity>(
        sortDescriptors: [ ... ],
        predicate: NSPredicate(format: "ofList == %@", list),
        animation: .default)
}

Is any of these better, more appropriate, more efficient towards view updates ... ?

Especially when I go deeper into the tree structure, it feels strange that all is relying on one first FetchRequest up the chain.

ChrisR
  • 9,523
  • 1
  • 8
  • 26
  • It is my understanding that each `@FetchRequest` takes some additional time. Also, once you have your fetch, isn't the memory already allocated? If it wasn't Core Data, how would you do it? Frankly, I don't see any drawbacks, and I see a bunch of advantages to using the tree structure. That being said, I have never used an extremely large data set in Core Data. At smaller sizes, the difference is probably pretty negligible. – Yrb Feb 11 '22 at 13:14
  • @Yrb thank you, that's what I hoped :) Your comment leads me to the question, whether the root fetchrequest really fetches the whole tree with all sub children at once ... – ChrisR Feb 11 '22 at 13:51
  • 1
    I found [the answer](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/Performance.html). The relationships are probably not fetched until needed. However, Apple recommends one, not many, `@FetchRequests`. Things are optimized and lazy loaded. – Yrb Feb 11 '22 at 14:06
  • Does this answer your question? [CoreData one-to-many relationship. Problem with NSSet attribution](https://stackoverflow.com/questions/68681841/coredata-one-to-many-relationship-problem-with-nsset-attribution) – lorem ipsum Feb 11 '22 at 14:37
  • 1
    accessing `allObjects` will be more efficient because you wouldn`t be creating extra listeners and all that goes into the `FetchRequest` access to the objects is already there. – lorem ipsum Feb 11 '22 at 14:40

1 Answers1

1

Overall it is best to use another @FetchRequest to fetch the child objects using the parent in the predicate, that is why we have inverse relations and means you can benefit to change tracking of the relation objects. However you will also need to wrap this child View inside an intermediate View so that when the parent View's body runs and inits all the child Views it doesn't needlessly re-fetch all the child fetch requests. This is because although @FetchRequest is a property wrapper, unlike @State it causes body to run every time its View is init, so you want to avoid that with the wrapper view that will not re-run the body when its the same parent object passed in. You can turn on SQL debugging to check what queries are hitting the database.

malhal
  • 26,330
  • 7
  • 115
  • 133