简体   繁体   中英

Parse.com local datastore: Tried to save an object with a new, unsaved child

I am testing Parse local datastore to evaluate if I can use it as a replacement for SQLite for an app that would mostly be used offline. I may have found a bug?

Consider the Product and Order classes:

class Product : PFObject, PFSubclassing {
    @NSManaged var productName: String!
}

class Order : PFObject, PFSubclassing {
    @NSManaged var orderId: String!
    @NSManaged var product: Product!
}

With internet disabled, when I run the following code, it crashes on the last line with Tried to save an object with a new, unsaved child.

let p = Product()
p.productName = "Test Product"
p.saveEventually()

let o = Order()
o.orderId = "TestOrder01"
o.product = p
o.saveEventually()

let query = Order.query()
query.whereKey("product", equalTo: p)

let results = query.findObjects() // crashes with Tried to save an object with a new, unsaved child.

is it a platform limitation or a bug in my code?

NOTE I have typed the code from memory, so ignore minor issues.

This is caused by your use of saveEventually causing a racing condition, like so:

  1. You create a Product.
  2. You tell Parse to save it when it has time - but it doesn't right away.
  3. You create an Order.
  4. When you tell Parse to save the order eventually, it checks to make sure the parent is already saved, which it isn't - hence the error.

You need to ensure the parent is saved before creating a child.

Instead, do a saveInBackGroundWithBlock on the Product, then do the creation and save of the Order in the completion block.

The method you may need pinObjectInBackground . This is actually how you save locally

The saveEventually method is used when you want to sync local data with the cloud. saveEventually pins but will save to the cloud the first chance it gets.

When you just pinObjectInBackground it saves it locally but will not attempt to save anything offline.

See the code below. Beware I changed it without XCODE, so it may have typos :) The code below will only look to satisfy your query from the local datastore. The "saveEventually" will push (sync) with Parse cloud, but if you are looking for data to be be locally available, it must be pinned, with or without a name.

let p = Product()
p.productName = "Test Product"
p.pinWithName("test")
p.saveEventually()

let o = Order()
o.orderId = "TestOrder01"
o.product = p

o.pinWithName("test")
o.saveEventually()

let query = Order.query()
query.fromPinWithName("test")
query.whereKey("product", equalTo: p)

let results = query.findObjects() 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM