Query with predicate in child view running too frequently.

I'm trying to determine if this is "expected" swiftui behavior or an issue with SwiftUI/Data which needs a feedback request...

When a child view has a Query containing a filter predicate, the query is run with each and every edit of the parent view, even when the edit has no impact on the child view (e.g. bindings not changing).

In the example below, ContentView has the TextField name, and while data is being entered in it, causes the Query in AddTestStageView to be run with each character typed, e.g. 30 characters result in 30 query executions.

(Need "-com.apple.CoreData.SQLDebug 1" launch argument to see SQL output).

Removing the filter predicate from the query and filtering in ForEach prevents the issue.

In my actual use case, the query has a relatively small result set (<100 rows), but I can see this as a performance issue with the larger result sets.

xcode/ios: 26.2

Repro example code:

import SwiftUI
import SwiftData

// Repro to Query filter issue in child view running multiple time unexpectedly

// Need "-com.apple.CoreData.SQLDebug 1" launch argument set to see SQL console output.


@main
struct ReproViewQueryMultipleRunningsApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(DataManager.shared.sharedModelContainer())
    }
}

@Model
final class TestStageClass {
   var id: UUID = UUID()
   var name: String = ""
   var isActive: Bool = true
   var displayOrder: Int = 0

   init(name: String, isActive: Bool, displayOrder: Int) {
      self.name = name
      self.isActive = isActive
      self.displayOrder = displayOrder
   }

}

struct ContentView: View {
   @Environment(\.modelContext) var modelContext

   @State private var name: String = ""
   @State private var selectedTestStage: TestStageClass = DataManager.shared.getFirstTestStageClass()

   var body: some View {
      VStack (spacing: 20) {
         TextField("Name", text: $name)

         AddTestStageView(selectedTestStage: $selectedTestStage)
      }
      .frame(height: 200)
   }
}

#Preview("Sample Data") {
   ContentView()
      .modelContainer(DataManager.shared.sharedModelContainer())
}


struct AddTestStageView: View {
   @Environment(\.modelContext) var modelContext
   @Binding var selectedTestStage: TestStageClass

   // MARK: - ISSUE LOCATION
   /// Using this Query with filter causes it to be run after each editing on parent view - such as each letter when editing a name.
   @Query(filter: #Predicate<TestStageClass> { $0.isActive }) private var testStageClasses: [TestStageClass]

   /// Using this query doesn't have the issue, then need filter in ForEach.
//   @Query() private var testStageClasses: [TestStageClass]

   var body: some View {
      Picker("stage", selection: $selectedTestStage) { // filter and sort here does not affect issue with above Query predicate filter.
         ForEach(testStageClasses.filter(\.isActive).sorted(by: { $0.displayOrder < $1.displayOrder } ), id: \.id) { stage in
            Text("\(stage.name)")
               .tag(stage)
         }
      }
   }
}


class DataManager {
   static let shared = DataManager()
   private var modelContainer: ModelContainer? = nil

   public func sharedModelContainer(inMemory: Bool = false) -> ModelContainer {
      let schema = Schema([TestStageClass.self])
      let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: inMemory)

      do {
         self.modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
         checkDataExists()
         return self.modelContainer!
      } catch {
         fatalError("Could not create sharedModelContainer. Schema:\(schema.entities.map(\.name)), \((modelConfiguration.isStoredInMemoryOnly) ? "in memory only" : "in disk"):\n\(error.localizedDescription)")
      }

   }

   private func checkDataExists() {
      let mainContext = self.modelContainer!.mainContext

      print("checkDataExists")

      do {
         let classData: [TestStageClass] = try mainContext.fetch(FetchDescriptor<TestStageClass>())

         if classData.isEmpty {
            mainContext.insert(TestStageClass(name: "Beginning", isActive: true, displayOrder: 0))
            mainContext.insert(TestStageClass(name: "Second Middle", isActive: false, displayOrder: 2))
            mainContext.insert(TestStageClass(name: "Middle", isActive: true, displayOrder: 1))
            mainContext.insert(TestStageClass(name: "End", isActive: true, displayOrder: 3))
         }

         if mainContext.hasChanges {
            try? mainContext.save()
            print("Added Default Data for TestStageClass")
         }

      } catch {
         fatalError("Failed to get item count for TestStageClass: \(error.localizedDescription)")
      }
   }

   func getFirstTestStageClass() -> TestStageClass {
      let mainContext = self.modelContainer!.mainContext

      var tmp: TestStageClass?

      do {
         let classData: [TestStageClass] = try mainContext.fetch(FetchDescriptor<TestStageClass>())

         tmp = classData.sorted(by: {$0.displayOrder < $1.displayOrder }).first

      } catch {
         fatalError("getFirstTestStageClass: \(error.localizedDescription)")
      }

      return tmp!
   }

}

Thanks, Steve

Query with predicate in child view running too frequently.
 
 
Q