2014-12-07 84 views
16

看起來好像我的NSPredicate在更新Core Data記錄時不起作用。在執行提取請求時,同樣的NSPredicate可以正常工作。Swift核心數據批量更新創建重複記錄而不是覆蓋

當我做了Batch Update,它只是創造了新的重複記錄而不是覆蓋現有的預期效果。爲什麼哦爲什麼?

這裏是我的代碼,做了更新:​​

let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate 

lazy var managedObjectContext : NSManagedObjectContext? = { 
    if let managedObjectContext = self.appDelegate.managedObjectContext { 
     return managedObjectContext 
    } 
    else { 
     return nil 
    } 
    }() 

func doesMessageExist(id: String) -> Bool { 
    let fetchRequest = NSFetchRequest(entityName: "ChatMessage") 
    let predicate = NSPredicate(format: "id == %@", id) 
    fetchRequest.predicate = predicate 
    fetchRequest.fetchLimit = 1 

    let count = managedObjectContext!.countForFetchRequest(fetchRequest, error: nil) 
    return (count > 0) ? true : false 
} 

func updateMessage(chatMessage: ChatMessage) { 
    var batchRequest = NSBatchUpdateRequest(entityName: "ChatMessage") 

    if doesMessageExist(chatMessage.id) { 
     batchRequest.predicate = NSPredicate(format: "id == %@", chatMessage.id) 
    } 

    batchRequest.propertiesToUpdate = [ 
     "id" : chatMessage.id, 
     "senderUserId" : chatMessage.senderUserId, 
     "senderUsername" : chatMessage.senderUsername, 
     "receiverUserId" : chatMessage.receiverUserId, 
     "receiverUsername" : chatMessage.receiverUsername, 
     "messageType" : chatMessage.messageType, 
     "message" : chatMessage.message, 
     "timestamp" : chatMessage.timestamp 
    ] 

    batchRequest.resultType = .UpdatedObjectsCountResultType 
    var error : NSError? 
    var results = self.managedObjectContext!.executeRequest(batchRequest, error: &error) as NSBatchUpdateResult 
    if error == nil { 
     println("Update Message: \(chatMessage.id) \(results.result)") 
     appDelegate.saveContext() 
    } 
    else { 
     println("Update Message Error: \(error?.localizedDescription)") 
    } 
} 

這裏是我的ChatMessage類:

class ChatMessage: NSManagedObject { 

    @NSManaged var id: String 
    @NSManaged var message: String 
    @NSManaged var messageType: String 
    @NSManaged var receiverUserId: String 
    @NSManaged var receiverUsername: String 
    @NSManaged var senderUserId: String 
    @NSManaged var senderUsername: String 
    @NSManaged var timestamp: NSDate 

} 

這裏是核心數據堆棧在我的AppDelegate:

lazy var applicationDocumentsDirectory: NSURL = { 
    // The directory the application uses to store the Core Data store file. This code uses a directory named "com.walintukai.LFDate" in the application's documents Application Support directory. 
    let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) 
    return urls[urls.count-1] as NSURL 
}() 

lazy var managedObjectModel: NSManagedObjectModel = { 
    // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model. 
    let modelURL = NSBundle.mainBundle().URLForResource("LFDate", withExtension: "momd")! 
    return NSManagedObjectModel(contentsOfURL: modelURL)! 
}() 

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { 
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail. 
    // Create the coordinator and store 
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) 
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("LFDate.sqlite") 
    var error: NSError? = nil 
    var failureReason = "There was an error creating or loading the application's saved data." 
    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil { 
     coordinator = nil 
     // Report any error we got. 
     let dict = NSMutableDictionary() 
     dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" 
     dict[NSLocalizedFailureReasonErrorKey] = failureReason 
     dict[NSUnderlyingErrorKey] = error 
     error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict) 
     // Replace this with code to handle the error appropriately. 
     // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
     NSLog("Unresolved error \(error), \(error!.userInfo)") 
     abort() 
    } 

    return coordinator 
}() 

lazy var managedObjectContext: NSManagedObjectContext? = { 
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail. 
    let coordinator = self.persistentStoreCoordinator 
    if coordinator == nil { 
     return nil 
    } 
    var managedObjectContext = NSManagedObjectContext() 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    managedObjectContext.mergePolicy = NSOverwriteMergePolicy 
    return managedObjectContext 
}() 

// MARK: - Core Data Saving support 

func saveContext() { 
    dispatch_async(dispatch_get_main_queue(),{ 
     if let moc = self.managedObjectContext { 
      var error: NSError? = nil 
      if moc.hasChanges && !moc.save(&error) { 
       // Replace this implementation with code to handle the error appropriately. 
       // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
       NSLog("Database Save Error: \(error), \(error!.userInfo)") 
       abort() 
      } 
     } 
    }); 
} 

回答

1

您的doesMessageExist功能是wron G。

您檢查計數的讀取請求不等於NSNotFound,它只會在錯誤的情況下做的。如果找不到消息,它將返回零,如果可以找到它,它將返回一個(或更多,如果你有多個具有相同ID的對象)。

目前你的代碼會說這個消息總是存在。

順便提一下,這個問題中的代碼都沒有創建新的對象,並且executeRequest不是NSManagedObjectContext上的方法,因此您應該在問題中包含您的實現。

+0

感謝您的回覆。我將我的'didMessageExist'返回函數改爲:'return(count> 0)? true:false;'。另外,'executeRequest'函數對我來說是'NSManagedObjectContext'的默認函數。我沒有實施「擴展」。我只是按照這個[鏈接]中的指示(http://jamesonquave.com/blog/core-data-in-swift-tutorial-part-1/)。我知道這是因爲println消息而產生重複記錄:'println(「Update Message:\(chatMessage.id)\(results.result)」)'。結果。結果編號在更新時會不斷上升。 – 2014-12-07 09:00:51

+0

在iOS 8.0中引入了'executeRequest()'和'NSBatchUpdateRequest'。它在[iOS 8.0 API Diffs/CoreData Changes](https://developer.apple.com/library/ios/releasenotes/General/iOS80APIDiffs/frameworks/CoreData.html)中列出,但[NSManagedObjectContext Class Reference](https ://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/index.html)尚未涵蓋它。 – 2014-12-07 09:19:19

+0

@MartinR'executeRequest'可能不會在類引用中被覆蓋,但它肯定是有效的,並且會對我的'Core Data'進行更改。雖然,如果它正常工作是另一回事,因爲它不關注我的'NSPredicate'。 – 2014-12-07 09:37:20

9

可悲的是,對於NSBatchUpdateRequest沒有文檔(可恥的是你,蘋果公司!)。但是,WWDC 2014會話225(這裏是ASCII transcript)涵蓋了批量更新請求。

在會議上,要提到的是批量更新繞過NSManagedObjectContext和持久存儲直接進行更改。所以,你必須自己刷新的對象:

So if you're interested in updating your database en masse, setting a flag on a particular column for example, and then reflecting those changes in the UI, you're going to need to get the results or the Managed Object IDs back, so you can tell the object, tell the Managed Object Context to refresh the objects with those IDs.

您必須指定其他resultType批量要求:

batchRequest.resultType = .UpdatedObjectIDsResultType 

,然後執行請求後,你必須使用的NSManagedObjectID返回數組刷新對象(從Big Nerd Ranch代碼示例中,在夫特重寫):

for objectsID in objectsIDs { 
    var error : NSError? = nil 
    if let object = context.existingObjectWithID(objectsID as NSManagedObjectID, error: &error) { 
     context.refreshObject(object, mergeChanges: true) 
    } 
} 
+0

這是一個巨大的改進,它不附帶文檔?來吧,蘋果 – 2015-01-10 01:22:40

+0

我不明白你爲什麼要這個執行I/O。相反,你應該使用'objectRegisteredForID'? – Andy 2015-11-08 15:43:39

+0

https://developer.apple.com/videos/play/wwdc2014/225/ – 2017-11-21 21:11:49

2

嘗試此代碼爲NSBatchUpdateRequest與出duplicatin g swift中的記錄

func batchUpdate{ 
     let appDelegate = UIApplication.shared.delegate as! AppDelegate 
     let managedContext = appDelegate.managedObjectContext 
     let batchRequest = NSBatchUpdateRequest(entityName: "ENTITY_NAME") 
     batchRequest.propertiesToUpdate = [ "PROPERTY_NAME" : "CHANGE_VALUE`enter code here`"] 
     batchRequest.resultType = .updatedObjectIDsResultType 

     do{ 
      let objectIDs = try managedContext.execute(batchRequest) as! NSBatchUpdateResult 
      let objects = objectIDs.result as! [NSManagedObjectID] 

      objects.forEach({ objID in 
       let managedObject = managedContext.object(with: objID) 
       managedContext.refresh(managedObject, mergeChanges: false) 
      }) 
     } catch { 
     } 
} 
+0

Mass Panreeenge Neeenge,Therikka Vidareeenge,Marana Mass。 – 2016-10-20 07:05:18