如何在一个 NSFetchRequest 中获取核心数据关系?
Posted
技术标签:
【中文标题】如何在一个 NSFetchRequest 中获取核心数据关系?【英文标题】:How to fetch core data relationships in one single NSFetchRequest? 【发布时间】:2016-06-02 14:52:03 【问题描述】:我有一个核心数据应用程序,其模型设置如下图所示:
关系是这样设置的:
类别>子类别>项目
现在,是否有可能在一次提取中从具有名为 categoryName 的相同属性的 Subcategory 和 Item 实体中获取对象?我认为这可以通过使用关系来完成,但是我使用的代码不起作用:
let fetchNote = NSFetchRequest(entityName: "Category")
fetchNote.predicate = NSPredicate(format: "ANY subcategory.name == %@ AND item.name == %@", "Badaue", "Badaue")
let notes = try! appDel.managedObjectContext.executeFetchRequest(fetchNote) as? [Category]
print(notes)
【问题讨论】:
什么不起作用? 请说明您要获取的实体 - 每次获取都将返回一个数组,其中包含 要么 类别对象,或 子类别对象,或项对象,但不是不同实体的混合。 当然。例如,我想获取 Category 实体并从 Subcategory 和 Item 实体中获取结果,这些实体具有名为“categoryName”的属性,值为“Badaue”。 对不起,我还是很困惑:如果你获取 Category 实体,你会从 Category 实体中得到结果。您可以使用谓词限制结果,但不能使用谓词从不同实体“获取结果”。 那么建立关系有什么用呢?我虽然可以通过关系获取数据。 【参考方案1】:为避免混淆,我建议将 item
重命名为 items
以反映这是一对多的关系。 subcategory
也是如此。
EDIT2 - 您要求获取具有特定categoryName
的Subcategory
和Item
对象,对吗?您上面编写的查询根本没有这样做。
首先,是的,您需要 2 个查询,因为您一次只能获取 1 个 Entity
类型。
其次,让我们重新编写你的语法,因为现在它非常危险。
do
let predicate = NSPredicate(format: "categoryName == %@", "yourCategoryHere")
let fetchSubcategory = NSFetchRequest(entityName: "Subcategory")
fetchSubcategory.predicate = predicate
if let subCategoryResults = try context.executeFetchRequest(fetchSubcategory) as? [Subcategory]
//do stuff
let fetchItem = NSFetchRequest(entityName: "Item")
fetchItem.predicate = predicate
if let itemResults = try context.executeFetchRequest(fetchItem) as? [Item]
//do stuff
catch
print(error)
【讨论】:
应用程序正在停止,当我设置异常断点时,它指向这行代码:let notes = try! appDel.managedObjectContext.executeFetchRequest(fetchNote) 为? [Category] 但它在日志屏幕上不输出任何内容。 如果我禁用异常断点,输出日志为:*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“此处不允许使用多对多键” 正如我所怀疑的那样 - 你不能查询to-many
关系的 to-many
关系。您需要编写两个单独的查询。【参考方案2】:
如果您获取Categories
,您将获得Category
对象的数组。这些对象中的每一个都有一个属性subcategory
,它是一个包含所有相关Subcategory
对象的集合。这些对象中的每一个都有一个属性item
,它是一个包含与Subcategory
相关的所有Item
对象的集合。相关对象“嵌套”在Category
和Subcategory
对象中。
当您获取类别时,您不需要指定谓词来获取相关对象。只要您访问subcategory
或item
属性,它们就会自动获取。因此,例如,如果 myCategory
是您获取的 Category
对象,
let mySubcategories = myCategory.subcategory
for subcat in mySubcategories
print("\(subcat)")
应该打印每个相关的子类别。
如果这些属性为 nil,则可能是您尚未建立关系。这通常在您第一次创建对象时完成。例如,如果您使用categoryName = "Badaue"
创建一个Subcategory
,您可以像这样与Category
和name = "Badaue"
建立关系:
let newSubcategory = ....
newSubcategory.categoryName = "Badaue"
let fetchCategory = NSFetchRequest(entityName: "Category")
fetchCategory.predicate = NSPredicate(format: "name == %@", newSubcategory.categoryName)
let categories = try! appDel.managedObjectContext.executeFetchRequest(fetchNote) as? [Category]
if (categories!.count > 0)
let firstCategory = categories[0]
newSubCategory.category = firstCategory
else
// no existing Category with the correct name, so create one....
let newCategory = ....
// ... and then establish the relationship to the Subcategory
newSubCategory.category = newCategory
【讨论】:
【参考方案3】:应该这样尝试: 我有两个实体 1. 触发器 2. 数字 关系是多对多的:- 一个触发器可以附加一个或多个手机号码,而该号码可能是触发器表中多个触发器的一部分。
步数:1
步骤:2
现在你会遇到这样的情况:
Xcode生成的代码是这样的。
import Foundation
import CoreData
extension MobileNumber
@nonobjc public class func fetchRequest() -> NSFetchRequest<MobileNumber>
return NSFetchRequest<MobileNumber>(entityName: "MobileNumber");
@NSManaged public var mNumber: String?
@NSManaged public var title: String?
@NSManaged public var triggers: NSSet?
// MARK: Generated accessors for triggers
extension MobileNumber
@objc(addTriggersObject:)
@NSManaged public func addToTriggers(_ value: Trigger)
@objc(removeTriggersObject:)
@NSManaged public func removeFromTriggers(_ value: Trigger)
@objc(addTriggers:)
@NSManaged public func addToTriggers(_ values: NSSet)
@objc(removeTriggers:)
@NSManaged public func removeFromTriggers(_ values: NSSet)
同样,您也会为其他实体生成类。 我已经定义了一个用于获取具有 UUID 的实体的函数,它对于我的 Trigger 表的所有行都是唯一的。
func fetchTriggerWithUUID(identifier: String) -> [Trigger]
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Trigger")
let predicate = NSPredicate(format: "uuid = %@", identifier)
fetchRequest.predicate = predicate
do
let results = try managedObjectContext.fetch(fetchRequest) as! [Trigger]
return results
catch let error as NSError
print(error)
return []
现在,无论我需要处理任何特定 [row] 的数据,或者您甚至可以处理一组 [rows],这在我的例子中都非常简单。
let result = AppDelegate.getAppDelegate().fetchTriggerWithUUID(identifier: notifIdentifier).first
numbers.removeAll()
for num in (result?.numbers)!
let numHere = num as! MobileNumber
numbers.append(numHere.mNumber!)
let messageHere = "Wanted to inform you! \n" + (result?.title)! + "\n" + (result?.desc)!
您可以在 [.xcdatamodelID] 文件中使用尽可能多的实体。
【讨论】:
以上是关于如何在一个 NSFetchRequest 中获取核心数据关系?的主要内容,如果未能解决你的问题,请参考以下文章
核心数据 NSFetchRequest 按类别排序方法返回值
你如何构造 NSFetchRequest setHavingPredicate: 的谓词?
如何在类方法中执行 Core Data NSFetchRequest?
在 NSArray 中获取 NSFetchRequest 的所有结果
NSFetchRequest 如何知道哪个托管对象上下文在范围内?
如何使用 NSExpression 使用自定义函数设置 NSFetchRequest propertiesToFetch