Select to view content in your preferred language

Error "Geodatabase Item not found" on updating feature with AGSGeodatabaseFeatureTable

1075
4
Jump to solution
03-21-2022 06:08 PM
ShiminCai
Frequent Contributor

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

  • BUG-000140772:  Applying edits on a ServiceFeatureTable fails against ArcGIS Enterprise 10.6.1 with the error “Geodatabase item not found.”

 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

0 Kudos
1 Solution

Accepted Solutions
Nicholas-Furness
Esri Regular Contributor

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!

View solution in original post

4 Replies
Nicholas-Furness
Esri Regular Contributor

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?

0 Kudos
ShiminCai
Frequent Contributor

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

0 Kudos
Nicholas-Furness
Esri Regular Contributor

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!

ShiminCai
Frequent Contributor

Hi Nick,

My problem has been fixed. Thank you so much for your help.

Cheers,

Shimin