TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Using UUID instead of relationships in CoreData: Looking for example

Forums > SwiftUI

@delawaremathguy in a response on UUID's in CoreData you said this:

(3) i also use UUIDs to keep the Core Data model a little flatter and the Core Data store more lean.

that is, rather than having relationships all throughout the object graph, it's sometimes sufficient in my case to record the UUID of one object B in another object A, instead of having a Core Data "one-to-many relationship pointer" from A to B. entity B no longer needs an NSSet? data type to record the inverse relationship. if i need to match up the appropriate B entity with A later, i can do a fetch for entities of B's type with their id: UUID matching A's UUID reference for B.

Are you storing all id's as UUID? In other words are you storing the id from object B in Object A as a UUID or as a string? Do you have a snippet showing how you reference the "relationship" in Swift to get all Object B's belonging to an specific Object A that you can share?

3      

hi Michael,

took a few minutes to remember this, but yes, i do have two active (but private) projects using some variant of this strategy.

(1) i give every Core Data entity an attribute id: UUID? ... not a string, but a real UUID. (well, Core Data marks it as an optional.)

(2) just for the record, i may have gotten the language reversed about what was an A and what was a B. even i am confused as i look back (!) so let's be concrete:

  • a Golfer has many golf Clubs. a Golfer entity has several attributes (name, etc.) and a Club entity has several attributes (manufacturer, model, iron/wood/putter/wedge, ...)
  • to denote that a Golfer owns a particular Club, we need a one-to-many relationship from Golfer to Club, as a Golfer owns many clubs, but a Club belongs only to one Golfer.
  • rather than implementing a relationship directly in Core Data, the Club entity will have an attribute of golferID: UUID?, which is the UUID of the Golfer who owns the club.

so, how do you match these up?

  • if you add a Club to a Golfer, just set the Club's golferID to the Golfer's id.
  • given a Golfer, you find her clubs by doing a Core Data fetch on Club objects which have their golferID equal to the golfer's Core Data id. this should be about right:
    func clubs(for golfer: Golfer) -> [Club] {
    let FetchRequest: NSFetchRequest<Club> = Club.fetchRequest()
    NSPredicate(format: "golferID == %@", golfer.id! as CVarArg)
    do {
            let clubs = try context.fetch(fetchRequest)
            return clubs
    } catch let error as NSError {
            NSLog("Error fetching clubs: \(error.localizedDescription), \(error.userInfo)")
    }
    return []
  • given a Club, you find its owner by doing a Core Data fetch on Golfer objects whose Core Data id is equal to the Club's golferID.
    func golfer(for club: Club) -> Golfer? {
    let FetchRequest: NSFetchRequest<Golfer> = Golfer.fetchRequest()
    NSPredicate(format: "id == %@", club.golferID! as CVarArg)
    do {
            let golfers = try context.fetch(fetchRequest)
            return golfers.first
    } catch let error as NSError {
            NSLog("Error fetching Golfers: \(error.localizedDescription), \(error.userInfo)")
    }
    return nil

it's an open question about whether this is the right thing to do. it comes down to a time-space tradeoff, perhaps; and there are ways to speed up the fetching ... e.g., keep a dictionary of golfers keyed by id, in which case golfer(for club: Club) becomes a simple lookup based on the value of club.golferID.

but in one case i had, the Core Data object graph had some "almost circular" relationships among three entities ... and SwiftUI (in particular) seemed very unhappy about this.

and in another case, i am using two separate Core Data stores (one a local configuration that stays on device, and a second that NSPersistentCloudKitContainer synchronizes across devices via CloudKit). there is no way to express a relationship between two Core Data entities that live in separate configurations other than to store the id of an object in one configuration into an object in the other configuration.

hope that helps, and feel free to contact me -- i am on GitHub.

DMG

(added after the fact: it took me a little bit of time to locate a link to the discussion that initiated Michael's question.)

4      

DMG, Thanks, I had been doing something similar prior to SwiftUI, I called the golferId a "parentId". So every Entity has an "id" and a "parentId". I haven't yet woked out the SwiftUI code for the third level or belwo, but when I do, I'll post it back here.

Think: Programs, Projects, Tasks, Sub-Tasks, and Notes at every level.

3      

hi Michael,

for what you describe ... i think ... Program is a parent (=owner) of some number of Projects, which is a parent (=owner) of some number of Tasks, which is a parent (=owner) of some number of SubTasks ... and any one of these four types is a parent (=owner) of some number of Notes.

i think Core Data can handle this quite easily with one-to-many relationships from parent to child, and i doubt there's much to gain by going down the UUID route. Core Data is scalable; and sometimes you will appreciate having only to use a single line of code to delete a Program in Core Data, since Core Data then deletes all its children, grandchildren, great grandchildren, and their associated note objects if you set up the relationship deletion rules in Core Data to be Cascade.

my concerns (not so well described months ago, i am afraid) did not involve such a simple hierarchy. honestly: unless there's a reason to use UUIDs and look-up code in place of using Core Data relationships, i'd avoid doing so.

i'll look forward to seeing what you might post in the future.

hope that helps,

DMG

4      

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.