一对多关系设置器

Posted

技术标签:

【中文标题】一对多关系设置器【英文标题】:One To Many Relationship setter 【发布时间】:2017-04-15 13:15:58 【问题描述】:

这是我第一次在 swift 中使用 Core Data。我真的很喜欢它,但确保我的 Appdelegate 保存等也是一个挑战。

问题

基本上我正在创建一个预算应用程序。一旦预算结束,我需要获取当前预算并将其存储到历史实体中。现在我有 2 个不同的实体在这里工作:

NewBudgetCreateMO 和 HistoryBudgetHolderMO。应该发生的是 HistoryBudgetHolder 应该将预算 (newBudgetCreateMO) 添加到它的一对多关系中。这是我的图表及其关系的图像。

现在,如果我设置正确,我应该允许通过添加它们在我的历史记录中拥有尽可能多的 NewBudgetCreateMO 吗?下面的代码是为我的 History 实体生成的代码,它显示它包含一个 NSSet

extension HistoryBudgetHolderMO 

@nonobjc public class func fetchRequest() -> NSFetchRequest<HistoryBudgetHolderMO> 
    return NSFetchRequest<HistoryBudgetHolderMO>(entityName: "HistoryBudgetHolder");


@NSManaged public var budgets: NSSet?



extension HistoryBudgetHolderMO 

@objc(addBudgetsObject:)
@NSManaged public func addToBudgets(_ value: NewBudgetCreateMO)

@objc(removeBudgetsObject:)
@NSManaged public func removeFromBudgets(_ value: NewBudgetCreateMO)

@objc(addBudgets:)
@NSManaged public func addToBudgets(_ values: NSSet)

@objc(removeBudgets:)
@NSManaged public func removeFromBudgets(_ values: NSSet)


所以我假设我可以只使用“addToBudgets”来添加一组数据,它似乎确实有效,但仅限于一个实例。

我在哪里添加

所以我在 HistoryBudgetHolderMO 上执行了一个获取请求,以查看数据库中是否有任何请求。如果没有,那么我从我的 App Delegate 创建一个新的(请注意:我已经在上面的方法中完成了应用委托转换等,然后将 App Delegate 和上下文传递给了这个方法)

private func SaveAndDeleteCurrentBudget(context : NSManagedObjectContext, appDele : AppDelegate)
    let fetchHistory : NSFetchRequest<HistoryBudgetHolderMO> = HistoryBudgetHolderMO.fetchRequest()

    //Saves the budget to the history budget. If we don't have oen we created one and add it to that
    do
        let historyBudgets : [HistoryBudgetHolderMO] = try context.fetch(fetchHistory)
        if historyBudgets.count <= 0
            let newHistoryBudget : HistoryBudgetHolderMO = HistoryBudgetHolderMO(context: context)
            newHistoryBudget.addToBudgets(budgetData.first!)
            print("entered new historyBudget")
        else
            historyBudgets.first!.addToBudgets(budgetData.first!)
        
        appDele.saveContext()
    catch
        print("Error when looking for history fetch result")
    

   //Deletes all budget data and budget entries that are currently used
    for object in budgetData
        context.delete(object)
    

    let fetchAllDataEntries = NSFetchRequest<NSFetchRequestResult>(entityName: "BudgetEntry")
    let deleteReq = NSBatchDeleteRequest(fetchRequest: fetchAllDataEntries)

    do
        try context.execute(deleteReq)
    catch
        print("Error when deleting budget entries")
    
    appDele.saveContext()

    我执行获取请求并检查是否存在历史实体。如果没有,那么我创建一个新条目,添加预算条目,然后保存上下文。 如果没有,那么我会获取历史记录持有者的第一个实例(因为应该只有一个,因为它只是一个容器),然后添加预算条目,然后保存。

哪里不好

所以当我第一次这样做并且它处于状态 2 时,我得到一个 Optional(1) 的值,这意味着它已经存储了一个历史条目。然而,在此之后的任何添加都一直说它是可选的(1)。我尝试查找无数解决方案,尝试弄乱扩展等。我认为这将是一个简单的 Get/Set 操作,但它只是不起作用。

对此的任何帮助将不胜感激。

感谢您花时间阅读本文。

【问题讨论】:

这到底是什么意思:“但是,在这之后还有更多的补充说它是可选的(1)。”?哪个属性是可选的(1)?为什么你要删除所有的'budgetData' 'for object in budgetData context.delete(object) ` 虽然你使用的是第一个,因为它已添加到 historyBudgets 对象中? 当我打印 NSSet 的长度时,“historyBudgets.first!.addToBudgets(budgetData.first!)”行总是返回 Optional 1(抱歉没有说清楚)。我删除了所有数据,因为该数据条目不应再是主要预算。应将其存档以允许创建新的 NewBudgetCreateMO。您是否认为比这更好的方法是创建一个新元素,但始终获取数组中的最后一个元素而不是第一个元素?那么我可以只使用预算条目作为历史条目吗? 【参考方案1】:

您的解决方案现在看起来不错。我还建议摆脱 HistoryBudgetHolderMO 课程。我可以建议向 NewBudget 类添加另一个字段/属性:一个 creationDate (日期类型)。这样,您始终可以获取最新的(例如,获取所有这些并按 creationDate 排序)。您还可以添加一个活动/历史布尔属性来将预算标记为活动/非活动。另一个建议是尽量避免强制展开。而不是写

budgetData.first!.attributeName 

尝试使用 'if let' 构造

if let budget = budgetData.first 
    budget.attributeName

【讨论】:

您按创建日期获取的想法也很棒。我不知道为什么我没有想到这一点(尤其是当我已经在存储日期时)。也是的,你是对的,我应该使用 if let more 来确保我没有得到任何 nil 值选项。我真的很感谢你的帮助卡拉。我会将此标记为答案,因为它和我自己的一样明智! @CardDeath 感谢您的接受,不客气!【参考方案2】:

任何感兴趣的人的解决方案

正如我之前提到的,我仍在学习 Core Data,我很感谢 KaraBenNensi 的评论让我思考。

是的,所以不需要“持有人”类型的对象。相反,我所做的是我使用了我的预算的最后一个索引。因此,每次我创建新预算时,我都会将它们全部保存在数组中。所以不要说:

budgetData.first!.attributeName 

我现在用

budgetData.last!.attributeName.

这意味着我的数据库会增长,但无论如何它都会随着历史持有者的增长而增长。现在,当我想显示历史记录时,我只需从budgetData 核心数据模型中获取所有结果。当我想显示我的实际预算时,我只需使用 .last 即可获得最近创建的预算。

我希望这对某人有所帮助,我很高兴我能弄清楚。如果将来有人需要帮助,请回复此问题,我会尽力提供帮助(但我不是专家!)

【讨论】:

attributeName 是什么意思?这只是一个例子吗? 是的,我只是说在核心数据的实体中找到的一个属性。所以说我想展示一些我会使用最后一个元素而不是像以前一样的第一个元素的数据。 :)

以上是关于一对多关系设置器的主要内容,如果未能解决你的问题,请参考以下文章

一对多和递归关系 - 强制设置值

关于与查询构建器的“一对多”关系的教义内连接

Swift 一对多关系

如何使用同一列休眠设置多个一对多关系

设置一对多关系后,NSFetchRequest 查询返回 nil

设置一对多关系 Core Data 和 Magical Record