Hi there,
Updating a feature with an AGSGeodatabaseFeatureTable fails and gets the "Geodatabase item not found" error:
geodatabaseFeatureTable?.update(updatedFeature, completion: { error in
if error != nil {
print(error.localizedDescription)
//"Geodatabase item not found"
}
})
It works fine with the feature service counterpart AGSServiceFeatureTable. Noticed it was a bug
on AGSServiceFeatureTable. https://community.esri.com/t5/arcgis-runtime-sdks-blog/announcing-arcgis-runtime-100-11-2/ba-p/10717...
I'm on ArcGIS Runtime SDK for iOS 100.13. Does anybody get any idea please?
Thanks,
Shimin
Solved! Go to Solution.
Thanks for the great repro case, @ShiminCai.
I'll share what we discussed via DM here in case others might find the explanation helpful.
You have this code in your repro app, which is creating a feature, adding it to the AGSGeodatabaseTable, then updating it:
@objc func sketchEditorGeometryDidChange() {
if sketchEditor.isSketchValid == true {
let newFeature = createNewFeature(geometry: sketchEditor.geometry!, featureLayer: featureLayer, featureTemplate: featureTemplate)
addFeature(newFeature: newFeature, featureLayer: featureLayer)
sketchEditor.stop()
updateFeature(feature: newFeature!)
}
}
func addFeature(newFeature: AGSFeature?, featureLayer: AGSFeatureLayer) {
if let featureTable = featureLayer.featureTable, featureTable is AGSGeodatabaseFeatureTable {
let geodatabaseFeatureTable = featureTable as! AGSGeodatabaseFeatureTable
geodatabaseFeatureTable.add(newFeature!, completion: { error in
if let error = error {
print("Error while adding feature: \(error.localizedDescription)")
return
}
})
}
}
func updateFeature(feature: AGSFeature) {
feature.attributes["SequenceNumber"] = sequenceNumber
featureLayer.featureTable!.update(feature, completion: { error in
if error != nil {
print(error!.localizedDescription)
//Geodatabase item not found.
} else {
self.sequenceNumber += 1
}
})
}
However, AGSGeodatabaseTable.add() is an asynchronous function, but you are not waiting for it to complete before you call AGSGeodatabaseTable.update(). So in other words, update() is being called to update an on-disk feature that isn't yet committed in the underlying .geodatabase file.
Changing your code to this fixes the issue:
@objc func sketchEditorGeometryDidChange() {
if sketchEditor.isSketchValid == true {
let newFeature = createNewFeature(geometry: sketchEditor.geometry!, featureLayer: featureLayer, featureTemplate: featureTemplate)
addFeature(newFeature: newFeature, featureLayer: featureLayer) { error in
if let error = error {
print("Error \(error.localizedDescription)")
return
}
self.updateFeature(feature: newFeature!)
}
sketchEditor.stop()
}
}
func addFeature(newFeature: AGSFeature?, featureLayer: AGSFeatureLayer, completion: @escaping (Error?) -> Void) {
if let featureTable = featureLayer.featureTable, featureTable is AGSGeodatabaseFeatureTable {
let geodatabaseFeatureTable = featureTable as! AGSGeodatabaseFeatureTable
geodatabaseFeatureTable.add(newFeature!, completion: { error in
if let error = error {
print("Error while adding feature: \(error.localizedDescription)")
completion(error)
return
}
completion(nil)
})
}
}
This code calls update() from the completion handler on add(), ensuring that add() has actually finished its work first.
In general, if a method has a completion block, it's safe to assume that until that completion block is called, the method won't have finished its work. Sometimes that's OK (for example, when setting a viewpoint on a map view) but other times it's critical to wait, as in this case.
Hope this helps!
Hi.
I think we would have to know more about the schema of the data. Do you have any domains or relationship classes defined in the data? Perhaps an attributed relationship?
Hi Nick,
I have prepared a reproducible Xcode project. What is the best way to send the zip file (382 mb) to you?
Thanks,
Shimin
Thanks for the great repro case, @ShiminCai.
I'll share what we discussed via DM here in case others might find the explanation helpful.
You have this code in your repro app, which is creating a feature, adding it to the AGSGeodatabaseTable, then updating it:
@objc func sketchEditorGeometryDidChange() {
if sketchEditor.isSketchValid == true {
let newFeature = createNewFeature(geometry: sketchEditor.geometry!, featureLayer: featureLayer, featureTemplate: featureTemplate)
addFeature(newFeature: newFeature, featureLayer: featureLayer)
sketchEditor.stop()
updateFeature(feature: newFeature!)
}
}
func addFeature(newFeature: AGSFeature?, featureLayer: AGSFeatureLayer) {
if let featureTable = featureLayer.featureTable, featureTable is AGSGeodatabaseFeatureTable {
let geodatabaseFeatureTable = featureTable as! AGSGeodatabaseFeatureTable
geodatabaseFeatureTable.add(newFeature!, completion: { error in
if let error = error {
print("Error while adding feature: \(error.localizedDescription)")
return
}
})
}
}
func updateFeature(feature: AGSFeature) {
feature.attributes["SequenceNumber"] = sequenceNumber
featureLayer.featureTable!.update(feature, completion: { error in
if error != nil {
print(error!.localizedDescription)
//Geodatabase item not found.
} else {
self.sequenceNumber += 1
}
})
}
However, AGSGeodatabaseTable.add() is an asynchronous function, but you are not waiting for it to complete before you call AGSGeodatabaseTable.update(). So in other words, update() is being called to update an on-disk feature that isn't yet committed in the underlying .geodatabase file.
Changing your code to this fixes the issue:
@objc func sketchEditorGeometryDidChange() {
if sketchEditor.isSketchValid == true {
let newFeature = createNewFeature(geometry: sketchEditor.geometry!, featureLayer: featureLayer, featureTemplate: featureTemplate)
addFeature(newFeature: newFeature, featureLayer: featureLayer) { error in
if let error = error {
print("Error \(error.localizedDescription)")
return
}
self.updateFeature(feature: newFeature!)
}
sketchEditor.stop()
}
}
func addFeature(newFeature: AGSFeature?, featureLayer: AGSFeatureLayer, completion: @escaping (Error?) -> Void) {
if let featureTable = featureLayer.featureTable, featureTable is AGSGeodatabaseFeatureTable {
let geodatabaseFeatureTable = featureTable as! AGSGeodatabaseFeatureTable
geodatabaseFeatureTable.add(newFeature!, completion: { error in
if let error = error {
print("Error while adding feature: \(error.localizedDescription)")
completion(error)
return
}
completion(nil)
})
}
}
This code calls update() from the completion handler on add(), ensuring that add() has actually finished its work first.
In general, if a method has a completion block, it's safe to assume that until that completion block is called, the method won't have finished its work. Sometimes that's OK (for example, when setting a viewpoint on a map view) but other times it's critical to wait, as in this case.
Hope this helps!
Hi Nick,
My problem has been fixed. Thank you so much for your help.
Cheers,
Shimin