Submission Date
2026-07-13
Status
Open
Area
SwiftData
Operating System Version
iOS 27 beta 3
Type
Incorrect/Unexpected Behavior
Description
Configuring propertiesToFetch on a FetchDescriptor has no effect on the generated SQL payload when executing a fetch pass via ModelContext.fetch(_:) or @Query.
When setting specific key paths in propertiesToFetch to optimize performance or memory layout (such as isolating a single String property for a sectioned layout or dynamic indexing pass), SwiftData silently overrides the optimization array. The underlying SQLite generation engine always expands the SELECT clause to include every single column mapped to the target entity, entirely defeating the utility of the public API property.
Steps to Reproduce
1 Create a basic @model class with multiple stored attributes.
2 Initialize a FetchDescriptor targeting that model.
3 Explicitly assign a subset of properties to descriptor.propertiesToFetch.
4 Run the fetch command via a ModelContext or bind it directly to a @query.
5 Observe the generated SQL trace output via the -com.apple.CoreData.SQLDebug 1 launch argument flag.
Example Implementation Code
@Model
class Person {
@Attribute(.unique) var id: String
var name: String
var age: Int
init(id: String, name: String, age: Int) {
self.id = id
self.name = name
self.age = age
}
}
// Inside a fetch pass:
var fetchDescriptor = FetchDescriptor<Person>()
fetchDescriptor.propertiesToFetch = [\.name] // Intent: Only pull the 'name' column
let results = try modelContext.fetch(fetchDescriptor)
Expected Behavior
The database should execute an optimized projection query, fetching only the columns mapped to the explicitly specified key paths in the propertiesToFetch array:
SELECT t0.Z_PK, t0.ZNAME FROM ZPERSON t0
Actual Behavior
The array constraint is ignored. The resulting SQL execution traces a full row pull across all properties:
SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZID, t0.ZNAME, t0.ZAGE FROM ZPERSON t0
Diagnostic Context & Root Cause Analysis
This issue appears to stem from a systemic translation gap between SwiftData's API layer and legacy Core Data behaviors. In Core Data, an NSFetchRequest only alters its column SELECT parameters if the request type is switched to .dictionaryResultType. If the context returns full managed object instances (NSManagedObjectResultType), Core Data requires complete records or uniform faults, ignoring partial requests.
Because SwiftData’s ModelContext and @Query initializers natively enforce returning arrays of full concrete models ([T]), the underlying Core Data framework forces a full row schema retrieval.
If propertiesToFetch cannot alter the column mapping for concrete PersistentModel fetches due to graph integrity guarantees, the property should either be removed from public FetchDescriptor exposure or integrated with a dedicated raw/projection dictionary query mode to prevent deceptive execution performance expectations.
Keywords
No response
Prerequisites
Submission Date
2026-07-13
Status
Open
Area
SwiftData
Operating System Version
iOS 27 beta 3
Type
Incorrect/Unexpected Behavior
Description
Configuring propertiesToFetch on a FetchDescriptor has no effect on the generated SQL payload when executing a fetch pass via
ModelContext.fetch(_:)or@Query.When setting specific key paths in
propertiesToFetchto optimize performance or memory layout (such as isolating a single String property for a sectioned layout or dynamic indexing pass), SwiftData silently overrides the optimization array. The underlying SQLite generation engine always expands theSELECTclause to include every single column mapped to the target entity, entirely defeating the utility of the public API property.Steps to Reproduce
1 Create a basic @model class with multiple stored attributes.
2 Initialize a FetchDescriptor targeting that model.
3 Explicitly assign a subset of properties to descriptor.propertiesToFetch.
4 Run the fetch command via a ModelContext or bind it directly to a @query.
5 Observe the generated SQL trace output via the -com.apple.CoreData.SQLDebug 1 launch argument flag.
Example Implementation Code
Expected Behavior
The database should execute an optimized projection query, fetching only the columns mapped to the explicitly specified key paths in the propertiesToFetch array:
Actual Behavior
The array constraint is ignored. The resulting SQL execution traces a full row pull across all properties:
Diagnostic Context & Root Cause Analysis
This issue appears to stem from a systemic translation gap between SwiftData's API layer and legacy Core Data behaviors. In Core Data, an
NSFetchRequestonly alters its columnSELECTparameters if the request type is switched to.dictionaryResultType. If the context returns full managed object instances (NSManagedObjectResultType), Core Data requires complete records or uniform faults, ignoring partial requests.Because SwiftData’s
ModelContextand@Queryinitializers natively enforce returning arrays of full concrete models ([T]), the underlying Core Data framework forces a full row schema retrieval.If propertiesToFetch cannot alter the column mapping for concrete
PersistentModelfetches due to graph integrity guarantees, the property should either be removed from publicFetchDescriptorexposure or integrated with a dedicated raw/projection dictionary query mode to prevent deceptive execution performance expectations.Keywords
No response
Prerequisites
FB<number>: <title>