核心数据一对多关系未正确/按预期保存

Posted

技术标签:

【中文标题】核心数据一对多关系未正确/按预期保存【英文标题】:Core Data One to Many Relationship not saving correctly/as expected 【发布时间】:2017-05-20 00:34:47 【问题描述】:

我有一个包含以下 NSManagedObjects 的核心数据项目:

********************** FSDJump NSManaged 对象

extension FSDJump 

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


@NSManaged public var starSystem: String
@NSManaged public var starPos: NSArray
@NSManaged public var bodyName: String
@NSManaged public var jumpDist: Float
@NSManaged public var fuelUsed: Float
@NSManaged public var fuelLevel: Float
@NSManaged public var boostUsed: Bool
@NSManaged public var systemFaction: String
@NSManaged public var systemAllegiance: String
@NSManaged public var systemEconomy: String
@NSManaged public var systemGoverment: String
@NSManaged public var systemSecurity: String
@NSManaged public var powers: NSArray
@NSManaged public var powerplayState: String
@NSManaged public var timeStamp: String
@NSManaged public var factionState: String
@NSManaged public var factions: NSSet

// MARK:为派系生成的访问器 扩展 FSDJump

@objc(addFactionsObject:)
@NSManaged public func addToFactions(_ value: Factions)

@objc(removeFactionsObject:)
@NSManaged public func removeFromFactions(_ value: Factions)

@objc(addFactions:)
@NSManaged public func addToFactions(_ values: NSSet)

@objc(removeFactions:)
@NSManaged public func removeFromFactions(_ values: NSSet)

********************** Factions NSManaged 对象

extension Factions 

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


@NSManaged public var name: String
@NSManaged public var allegiance: String
@NSManaged public var factionState: String
@NSManaged public var government: String
@NSManaged public var influence: Float
@NSManaged public var fsdJump: FSDJump

在 FSDJump 和 Factions 之间定义了一对多的关系(即一个 FSDJump 可能有多个派系(反向关系定义为“fsdJump”)。

我使用以下代码在“if else”语句中保存多个 Faction(它们存在的地方),从而保存每个 fsdJumpEvent。

                if fsdJumpEvent["Factions"].exists() 

                // save all of the Faction array objects in the variable arrayOfFactions
                let arrayOfFactions = fsdJumpEvent["Factions"]

                // create a newFaction managedObject to save the faction details to
                let newFaction = (Factions(context: contextTCCEDJ))
                for faction in arrayOfFactions 

                    // the following is strictly not necesary but it makes the code easier to read
                    // first allocate the values from faction to a local variable then allocate that variable to the newFaction managedObject
                    // Note faction is a tuple (string, JSON) so the construct 'faction.1' accesses the second value in the tuple
                    // 'faction.0' would access the first value in the tuple which is the array index "0", "1", "2", etc
                    let newFactionName = faction.1["Name"].string!
                    let newFactionState = faction.1["FactionState"].string!
                    let newFactionGovernment = faction.1["Government"].string!
                    let newFactionAllegiance = faction.1["Allegiance"].string!
                    let newFactionInfluence = faction.1["Influence"].float!

                    newFaction.name = newFactionName
                    newFaction.allegiance = newFactionAllegiance
                    newFaction.government = newFactionGovernment
                    newFaction.influence = newFactionInfluence
                    newFaction.factionState = newFactionState
                    // Add the new object to the context allowing it to be saved.
                    fsdJump.addToFactions(newFaction)
                    print("Faction added \(newFaction)")
                
            

代码似乎可以工作。它构建、运行,print("Faction added \(newFaction)") 语句在每个 FSDJump 存在时按预期打印多个 Faction,并且根据我正在使用的源数据文件 (JSON)。

我可以获取结果并将它们显示在 NSTableView 中。我可以毫无问题地加载 FSDJump 托管对象的数据并将其显示在 NSTableView 中。

获取代码为:

    // Function returns all of the Factions associated with the timeStamp related entry in FSDJumps using the fsdJump relationship
func eventFactionsFetchSavedDataFromPersistenStore (contextTCCEDJ: NSManagedObjectContext, timeStamp: String) -> [Factions] 
    var result = Array<Factions>()
    let localFetchRequest = Factions.fetchRequest() as NSFetchRequest
    localFetchRequest.predicate = NSPredicate(format:"fsdJump.timeStamp == '\(timeStamp)'")
    do 
        result = try contextTCCEDJ.fetch(localFetchRequest)
     catch 
        print("Error in returning Factions event saved data from the persistent store")
    
   print(result.count)
    for reSult in result 
    print(reSult.fsdJump.timeStamp)
    
    return result

然而,它似乎只保存了每个关系的最后一个“派系”——而不是for faction in arrayOfFactions 循环中显示的多个派系。因为 fetch 语句每次 fetch 只返回一个 Faction。即使我删除了谓词语句,它也会返回所有已保存的派系,但每个 fsdJumpEvent 也只保存了一个派系,而不是 print 语句标识的多个派系。

我已经尝试了我能想到的一切。我无法找到与此特定问题相关的先前问题。

我是否错误地使用了“addToFactions”功能?

如有任何帮助,我们将不胜感激。

(是的 - 对于任何 Elite Dangerous 粉丝,我正在编写一个 macOS 应用程序来解析我的日志文件作为我的 Windows 版本的 Elite Dangerous 的配套应用程序。)

【问题讨论】:

【参考方案1】:

您正在 for faction in arrayOfFactions 循环之外创建一个新的 newFaction 实例。因此,每次循环运行时都会使用单个 newFaction 并为其分配新值(覆盖以前的值),从而导致它以最后一组值结束。因此,您会看到具有“最后”一组值的单个派系。移动线: Let newFaction = Factions(context: contectTCCEDJ) for in 循环的内部(开头)。

编辑:您正在将您的派系添加到一个集合(根据定义,这需要独特的实体),因此您当前所做的只是每次都重新添加相同的派系,而不是一个新的派系。多对多关系指向一个集合。

【讨论】:

以上是关于核心数据一对多关系未正确/按预期保存的主要内容,如果未能解决你的问题,请参考以下文章

核心数据:一对多关系 - 没有保存细节

排除某些对象的一对多关系上的 NSFetchRequest 无法按预期工作

核心数据:在一对多关系中按日期属性排序

如何使用 Objective-C 将一对多关系数据保存到核心数据中

一对多关系核心数据只保存最后一个对象。其他人不见了

获取一对多的核心数据关系第一次返回正确的对象,但其他时候返回空集