当你有关系时,从不同的API保存到coredata。

问题描述 投票:0回答:1

我有两个不同的API来获取账户和联系人,在Core-Data模型中,我做了一个反向关系,假设一个账户可以有很多联系人。我的问题是,当我在通讯录屏幕上(当我使用账户ID调用GET联系人API时),什么是将这些联系人保存到该特定账户的最佳方式。实体关系如下。

enter image description here

我的部分完成的代码如下,但我想它是错误的,因为当我取回他们时,我得到的联系人是零。

 func saveContactfor(accountID:String,data:[Array],isAddedFromDevice:Bool) {
    let request:NSFetchRequest<Account> = Account.fetchRequest()

           do {
               let searchResults = try managedObjectContext.fetch(request)
                   for account in searchResults {

                      if account.account_Id == accountID {
                       print("ID found in already saved Accounts")
                        for contact in data {

                            account.contacts?.adding(contact.dictionary) //contact.dictionary-> i have written a utils method to convert an object array to [[String:String]] which is an array of dictionaries
                        }
                        try managedObjectContext.save()
                      }


                    }


           print("Contacts Updated")
           } catch {
            print("Error in saving contacts from api to coredata")
           }
}
ios swift core-data swift5
1个回答
-1
投票

由于你使用的是关系,你应该很接近你需要做的事情。所有的项目都需要更新,账户和联系人,所以你需要添加关系的一种方式或另一种方式。

另一种方法是使用 contact.account = account 这看起来更合理。

在你提供的代码中,我对一些事情感到困惑。

  1. 你是如何添加联系人的 这是不是应该是 account.contacts = account.contacts?.adding(contact.dictionary)?
  2. 为什么你要提取所有的联系人?使用谓词只提取那些给定ID的联系人。
  3. 可能的旧账户应该被删除吗?

我希望你的(伪)代码看起来像这样。

func saveContacts(_ contacts: [ContactDetailModel], forAccount accountID: String) throws {
    // Fetch or create an account
    let account: Account = try Account.findWithID(accountID) ?? Account.createNewInstance(accountID: accountID)
    // Assign account
    contacts.forEach { $0.account = account }
    // Save database
    try saveContext()
}

我想你应该可以想象这三个方法能帮你做什么。请记住,你可以通过使用 throws 在这种情况下,可以是巨大的便利。

现在要想还清旧账,可能还需要做一些工作。

func saveContacts(_ contacts: [InputContactData], forAccount accountID: String) throws {
    // Fetch or create an account
    let account: Account = try Account.findWithID(accountID) ?? try Account.createNewInstance(accountID: accountID)

    // Match accounts
    // Get all current contacts
    var depletingContacts: [ContactDetailModel] = (account.contacts.allObjects as? [ContactDetailModel]) ?? [ContactDetailModel]()
    contacts.forEach { newContact in
        if let index = depletingContacts.firstIndex { $0.contactID == newContact.id } {
            // The contact with this ID already exists. Remove it from array and assign new values
            let contact: ContactDetailModel = try depletingContacts.remove(at: index)
            contact.fillWithInputData(newContact)
        } else {
            // This contact is not yet in database. A new item needs to be created
            let contact: ContactDetailModel = try ContactDetailModel.newInstance()
            contact.fillWithInputData(newContact)
            contact.account = account
        }
    }
    // Clean up all old contacts.
    // The contact that are still left in depletingContacts were not part of input contacts and need to be deleted
    depletingContacts.forEach { try $0.removeFromDatabase() }


    // Save database
    try saveContext()
}

现在又进了一步. 我添加了 InputContactData 这是你从你使用的任何服务中接收到的数据,还不在核心数据中。

然后找到或创建一个账户。当迭代每一个新的联系人时,代码会首先尝试将一个现有的联系人与一个新的项目进行匹配。要么更新一个现有的项目,要么创建一个新的项目。由于现有的项目会从现有联系人数组中删除(耗尽),所以耗尽的数组会剩下已经被删除的联系人。因此,所有这些都可以从数据库中删除。

这是一个关系是一对多的过程。多对多也有类似的方法,但有点不同。

我希望剩下的代码能说明问题。

© www.soinside.com 2019 - 2024. All rights reserved.