多对多关系如何运作。

Posted

技术标签:

【中文标题】多对多关系如何运作。【英文标题】:How does many to many relationships work. 【发布时间】:2017-04-15 01:08:58 【问题描述】:

好的,我已经阅读了苹果Core Data Guide。我也在网上看,但只找到大约 2 年前的帖子。所以我不知道有多少关系有效。我正在使用核心数据构建应用程序。该应用有 3 个实体 PokemonTypeAbility强>。口袋妖怪可以有一种或多种类型,所以我将关系设置为多。一个类型可以有多个与之关联的口袋妖怪,所以我也应该将关系设置为多对多,但我不理解多对多关系。能力也是一样。这就是我的数据模型的样子。还有另外 2 个实体,但我现在并不真正关心这些。

这是我用来解析以下API 的函数。它获取前 20 个 Pokemon 保存名称并使用 url 获取有关该 Pokemon 的更多信息。所以我添加了另一个任务,为那个口袋妖怪添加类型和能力。

private func loadPokemon(url: String) 
    let context = coreData.persistentContainer.viewContext
    let request = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: request)  (data, response, error) in
        if error != nil 
            print(error!)
        

        do 
           let jsonResults = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
            let pokemonArray = jsonResults.value(forKey: "results") as! [[String: Any]]

            for pokemonData in pokemonArray 

                guard let name = pokemonData["name"] as? String else 
                    return
                

                guard let pokemonInfoURL = pokemonData["url"] as? String else 
                    return
                

                let pokemon = Pokemon(context: context)
                pokemon.name = name
                print(1)

                self.pokemonMoreInfo(for: pokemon, url: pokemonInfoURL, context: context)

            
        
        catch let err 
            print(err.localizedDescription)
        
    
    task.resume()


private func pokemonMoreInfo(for pokemon: Pokemon, url: String, context: NSManagedObjectContext) 
    let request = URLRequest(url: URL(string: url)!)
    let task = URLSession.shared.dataTask(with: request)  (data, response, error) in
        if error != nil 
            print(error!)
        

        do 
            let jsonResults = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary


            //MARK: Pokemon Abilities
            if let abilityArray = jsonResults.value(forKey: "abilities") as? [[String: Any]] 
                let abilities = pokemon.ability?.mutableCopy() as! NSMutableSet

                for abilityData in abilityArray 

                    guard let abilityDic = abilityData["ability"] as? NSDictionary else 
                        return
                    
                    let name = abilityDic.value(forKey: "name") as! String

                    guard let isHidden = abilityData["is_hidden"] as? Bool else 
                        return
                    

                    guard let slot = abilityData["slot"] as? Int16 else 
                        return
                    

                    let ability = Ability(context: context)
                    ability.name = name
                    ability.isHidden = isHidden
                    ability.slot = slot

                    abilities.add(ability)
                    pokemon.addToAbility(abilities)
                
            

            //MARK: Pokemon Type
            if let typeArray = jsonResults.value(forKey: "types") as? [[String: Any]] 
                let types = pokemon.type?.mutableCopy() as! NSMutableSet

                for typeData in typeArray 

                    guard let typeDic = typeData["type"] as? NSDictionary else 
                        return
                    
                    let name = typeDic.value(forKey: "name") as! String

                    guard let slot = typeData["slot"] as? Int16 else 
                        return
                    

                    let type = Type(context: context)
                    type.name = name
                    type.slot = slot

                    types.add(type)
                    pokemon.addToType(types)
                
            
        
        catch let err 
            print(err.localizedDescription)
        
        self.coreData.saveContext()
    
    task.resume()

我正在使用这个名为 SQLight Read-Only 的应用程序。能力和类型与正确的口袋妖怪匹配。这些是我的 SQLight 的截图。

我不确定你们是否知道 Pokemon,但喷火龙类型是 fireflying并拥有太阳能烈焰人的能力。所以我知道我正在正确保存数据。但是我的 SQLight 具有相同的重复类型,例如 firegrasspoison em> 同样适用于能力,但与正确的口袋妖怪相关联。这就是我完整的 SQLight 的样子。

不确定它是否会以多对多关系重复。所以我的问题是我如何使用与 Pokemon 的多对多关系来 type能力。那么如何添加具有相同类型或相同能力的口袋妖怪。所以稍后,我可以执行抓取所有具有火类型或相同能力的口袋妖怪。我不确定我是否正确解释了我的问题可能有点令人困惑。

不胜感激。 :)

【问题讨论】:

Core Data 是一个对象持久化系统,而不是一个 sql 数据库。我建议您不要尝试分析底层的 sql 数据存储。只需将对象引用设置为 Pokemon 的 type 属性,然后让 CoreData 更新引用。 【参考方案1】:

编辑: 实际上,我在下面写的内容对于 Core Data 是不正确的。 (感谢您在 cmets Paulw11 中指出这一点。)来自Core Data Guide:

多对多关系

您使用二对多关系定义多对多关系。第一个多对多关系从第一个实体(源实体)到第二个实体(目标)。第二对多关系从第二个实体(原始目标实体)到第一个实体(原始源实体)。然后,您将每个设置为另一个的倒数。 (如果您有数据库管理背景并且这引起您的担忧,请不要担心:如果您使用 SQLite 存储,Core Data 会自动为您创建中间连接表。)


旧答案(Core Data 不正确): 要在关系数据库中创建多对多关系,您必须添加一个帮助表。在您的情况下,您可以将其称为 PokemonWithType。它有两列,一列用于 Pokemon id,另一列用于 Type id。如果您想查找某个特定口袋妖怪的所有类型,您只需使用特定口袋妖怪 id 查询 PokemonWithType 中的所有条目。如果您想查找所有具有特定类型的口袋妖怪,您只需使用类型 id 即可。

【讨论】:

你好本杰明,你能提供截图或示例代码吗?如果可以的话,将不胜感激。 :) CoreData 直接支持多对多关系。虽然它可以由 SQLite 支持,但它是一个对象持久性系统,而不是数据库。 是的。我更正了我的答案。 @Luis - 您需要添加从能力到口袋妖怪和从类型到口袋妖怪的多对多关系。然后应该出现所需的关系。抱歉,我现在无法提供屏幕截图。

以上是关于多对多关系如何运作。的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy如何反映多对多关系

如何在多对多关系中更新日期

SQLite,多对多关系,如何聚合?

如何在后端创建多对多关系

如何查询多对多关系sequelize?

如何创建如何在 typeorm 中创建多对多关系,[NestJS]