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

Is it possible to query multiple different Element types from a SwiftData data model at once?

Forums > SwiftUI

So, lets say I have a data model for different types of vehicles. Since SwiftData is not compatible with Subclassing, I would have to make each type of vehicle its own separate class

@Model
class Car {
    var make: String
    var model: String
    ...
}

@Model
class AirPlane {
    var make: String
    var model: String
    ...
}  

@Model
class Boat {
    var make: String
    var model: String
    ...
}

Then, I can add a ModelContainer to my app that will hold all of these Elements

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: [Car.self, AirPlane.self, Boat.self])
    }

    init() {
        print(URL.applicationSupportDirectory.path(percentEncoded: false))
    }
}

But what if I want my app to show a list of all of the vehicles that have been added to my data model?

I haven't seen any examples where a Query can retrieve the data for multiple elements, so is this not possible to do?

I can write 3 separate queries, but then they won't all be combined into a single array that I can make a list from, so they would all basically be in their own separate lists, rather than blended together.

@Query(
    sort: [SortDescriptor(\Car.make, comparator: .localizedStandard), SortDescriptor(\Car.model, comparator: .localizedStandard)]
) var cars: [Car]

@Query(
    sort: [SortDescriptor(\AirPlane.make, comparator: .localizedStandard), SortDescriptor(\AirPlane.model, comparator: .localizedStandard)]
) var airPlanes: [AirPlane]

@Query(
    sort: [SortDescriptor(\Boat.make, comparator: .localizedStandard), SortDescriptor(\Boat.model, comparator: .localizedStandard)]
) var boats: [Boat]

Maybe I could make some kind of Protocol that all of these conform to.

protocol Vehicle {
   var make { get set }
   var model { get set }
}

I'm not sure if that would work, but even then, it seems I would have to write 3 separate queries, and then add them together in an [Vehicle] array...

var vehicles: [Vehicle] {
    cars + airPlanes + boats
}

If that would work then I could at least show them in a list together, but it might be difficult to make sure that deleting from the list is handled properly and everything.

I just don't know if there is a better solution for this that anybody knows of?

3      

In Core Data (not Swift Data), in the model editor, you can define Vehicle as an Abstract Entity and the others as its child entities (non-abstract).

Donny Wals' excellent Core Data book explains this.

3      

Unfortunately, SwiftData does not support abstract classes or child contexts.

3      

@DaveC  

Based on the code you shared, it appears that there are additional properties for each class that you omitted, so this may not work, but could you consider having a single "Vehicle" class with one of the properties being "type" or "vehicleType" to distinguish cars, airplanes, etc.?

3      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

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

Reply to this topic…

You need to create an account or log in to reply.

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.