title: What are some reliable mechanism to prevent data duplication in CoreData CloudKit?
body: <p>Every of our data row, contains an unique <code>uuid</code> column.</p>
  <p>Previously, before adopting CloudKit, the <code>uuid</code> column has a unique constraint. This enables us to prevent data duplication.</p>
  <p>Now, we start to integrate CloudKit, into our existing CoreData. Such unique constraint is removed. The following user flow, will cause data duplication.</p>
  <h2>Steps to cause data duplication when using CloudKit</h2>
  <ol>
  <li>Launch the app for the first time.</li>
  <li>Since there is empty data, a pre-defined data with pre-defined <code>uuid</code> is generated.</li>
  <li>The pre-defined data is sync to iCloud.</li>
  <li>The app is uninstalled.</li>
  <li>The app is re-installed.</li>
  <li>Launch the app for the first time.</li>
  <li>Since there is empty data, a pre-defined data with pre-defined <code>uuid</code> is generated.</li>
  <li>Previous old pre-defined data from step 3, is sync to the device.</li>
  <li>We are now having 2 pre-defined data with same <code>uuid</code>! :(</li>
  </ol>
  <p>I was wondering, is there a way for us to prevent such duplication?</p>
  <p>In step 8, we wish we have a way to execute such logic before written into CoreData</p>
  <blockquote>
  <p>Check whether such uuid exists in CoreData. If not, write to CoreData.
  If not, we will pick the one with latest update date, then overwrite
  the existing data.</p>
  </blockquote>
  <p>I once try to insert the above logic into <a href="https://developer.apple.com/documentation/coredata/nsmanagedobject/1506209-willsave" rel="nofollow noreferrer">https://developer.apple.com/documentation/coredata/nsmanagedobject/1506209-willsave</a> . To prevent save, I am using <code>self.managedObjectContext?.rollback()</code>. But it just crash.</p>
  <p><em>Do you have any idea, what are some reliable mechanism I can use, to prevent data duplication in CoreData CloudKit?</em></p>
  <hr />
  <h2>Additional info:</h2>
  <h2>Before adopting CloudKit</h2>
  <p>We are using using the following CoreData stack</p>
  <pre><code>class CoreDataStack {
      static let INSTANCE = CoreDataStack()
      
      private init() {
      }
      
      private(set) lazy var persistentContainer: NSPersistentContainer = {
          precondition(Thread.isMainThread)
          
          let container = NSPersistentContainer(name: &quot;xxx&quot;, managedObjectModel: NSManagedObjectModel.wenote)
          
          container.loadPersistentStores(completionHandler: { (storeDescription, error) in
              if let error = error as NSError? {
                  // This is a serious fatal error. We will just simply terminate the app, rather than using error_log.
                  fatalError(&quot;Unresolved error \(error), \(error.userInfo)&quot;)
              }
          })
          
          // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from
          // persistent store.
          container.viewContext.automaticallyMergesChangesFromParent = true
          
          // TODO: Not sure these are required...
          //
          //container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
          //container.viewContext.undoManager = nil
          //container.viewContext.shouldDeleteInaccessibleFaults = true
          
          return container
      }()
  </code></pre>
  <p>Our CoreData data schema has</p>
  <ol>
  <li>Unique constraint.</li>
  <li><strong>Deny</strong> deletion rule for relationship.</li>
  <li>Not having default value for non-null field.</li>
  </ol>
  <hr />
  <h2>After adopting CloudKit</h2>
  <pre><code>class CoreDataStack {
      static let INSTANCE = CoreDataStack()
      
      private init() {
      }
      
      private(set) lazy var persistentContainer: NSPersistentContainer = {
          precondition(Thread.isMainThread)
          
          let container = NSPersistentCloudKitContainer(name: &quot;xxx&quot;, managedObjectModel: NSManagedObjectModel.wenote)
          
          container.loadPersistentStores(completionHandler: { (storeDescription, error) in
              if let error = error as NSError? {
                  // This is a serious fatal error. We will just simply terminate the app, rather than using error_log.
                  fatalError(&quot;Unresolved error \(error), \(error.userInfo)&quot;)
              }
          })
          
          // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from
          // persistent store.
          container.viewContext.automaticallyMergesChangesFromParent = true
          
          // TODO: Not sure these are required...
          //
          //container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
          //container.viewContext.undoManager = nil
          //container.viewContext.shouldDeleteInaccessibleFaults = true
          
          return container
      }()
  </code></pre>
  <p>We change the CoreData data schema to</p>
  <ol>
  <li><strong>Not having</strong> unique constraint.</li>
  <li><strong>Nullify</strong> deletion rule for relationship.</li>
  <li>Having default value for non-null field.</li>
  </ol>
  <hr />
  <p>Based on a feedback of a Developer Technical Support engineer from <a href="https://developer.apple.com/forums/thread/699634?login=true" rel="nofollow noreferrer">https://developer.apple.com/forums/thread/699634?login=true</a> , hen mentioned we can</p>
  <ol>
  <li>Detecting Relevant Changes by Consuming Store Persistent History</li>
  <li>Removing Duplicate Data</li>
  </ol>
  <p>But, it isn't entirely clear on how it should be implemented, as the github link provided is broken.</p>