Swift Core Data按ID查询失败,按名称查询正常问题求助
问题描述
正在进行单元测试,验证Core Data操作时遇到问题:数据库中存在一条FoodItem实体记录:
<EasyFPU.FoodItem: 0x6000021b00f0> (entity: FoodItem; id: 0x6000002a02c0 <x-coredata://55F63A9D-9195-4991-8B24-8A3FF6301B1E/FoodItem/p6>; data: { caloriesPer100g = 72; carbsPer100g = "10.4"; category = Product; composedFoodItem = nil; favorite = 0; id = "220458AD-3216-45A2-9FC3-32285A2A36D0"; ingredients = ( ); name = Alpenzwerg; sugarsPer100g = "9.4"; typicalAmounts = ( ); })
使用按名称查询的函数可以正常获取该记录:
static func getFoodItemByName(name: String) -> FoodItem? { let predicate = NSPredicate(format: "name == %@", name) let request: NSFetchRequest<FoodItem> = FoodItem.fetchRequest() request.predicate = predicate if let result = try? CoreDataStack.viewContext.fetch(request) { if !result.isEmpty { return result[0] } } return nil }
但使用按ID查询的函数却返回空结果:
static func getFoodItemByID(_ id: String) -> FoodItem? { let predicate = NSPredicate(format: "id == %@", id) let request: NSFetchRequest<FoodItem> = FoodItem.fetchRequest() request.predicate = predicate if let result = try? CoreDataStack.viewContext.fetch(request) { if !result.isEmpty { return result[0] } } return nil }
数据模型定义如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23231" systemVersion="24A335" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier=""> <entity name="FoodItem" representedClassName=".FoodItem" syncable="YES"> <attribute name="caloriesPer100g" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="carbsPer100g" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="category" optional="YES" attributeType="String"/> <attribute name="favorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/> <attribute name="id" optional="YES" attributeType="UUID" usesScalarValueType="NO"/> <attribute name="name" optional="YES" attributeType="String"/> <attribute name="sugarsPer100g" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/> <relationship name="composedFoodItem" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ComposedFoodItem" inverseName="foodItem" inverseEntity="ComposedFoodItem"/> <relationship name="ingredients" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Ingredient" inverseName="foodItem" inverseEntity="Ingredient"/> <relationship name="typicalAmounts" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="TypicalAmount" inverseName="foodItem" inverseEntity="TypicalAmount"/> </entity> </model>
两处查询代码逻辑一致,使用同一数据库,请问问题出在哪里?
问题原因及解决方案
问题核心是数据类型不匹配:
- 数据模型中
id字段的类型是UUID,但查询时传入的是String类型的ID字符串,直接用字符串和UUID实例比较会完全不匹配,导致查询无结果。 - 而
name字段本身就是String类型,所以按名称查询可以正常工作。
有两种修正方案可选:
- 修改查询函数,将字符串转为UUID
先把传入的字符串ID转换成UUID实例,再用于谓词查询:static func getFoodItemByID(_ id: String) -> FoodItem? { guard let uuid = UUID(uuidString: id) else { return nil // 处理无效UUID字符串的情况 } let predicate = NSPredicate(format: "id == %@", uuid as CVarArg) let request: NSFetchRequest<FoodItem> = FoodItem.fetchRequest() request.predicate = predicate return try? CoreDataStack.viewContext.fetch(request).first } - 修改数据模型,将
id字段类型改为String
如果业务场景更适合用字符串存储ID,可以直接在Core Data模型编辑器中,把id的属性类型从UUID改为String,原查询代码无需修改即可正常运行。
注意:若选择修改数据模型,需做好已有数据的迁移处理,避免数据丢失。
内容的提问来源于stack exchange,提问作者Ulrich
相关产品推荐
相关产品推荐

