Getting an "Operation is not valid due to the current state of the object" error. What am I missing?

2312
1
Jump to solution
06-02-2017 07:18 AM
ufshall
New Contributor II

I am writing a task that will copy the features of a feature class to an SDE feature class. I can compile the program and complete the task without error until I actually try to run the Create command on the edit operation. Once I add that line I receive an AggregateException error stating:

"Cannot obtain value of the local variable or argument because it is not available at this instruction pointer, possibly because it has been optimized away."

Looking online, I find solutions telling you to uncheck the Optimize Code option in the Build properties and making sure the "Suppress JIT optimization" is checked in the Debug Options. I have tried both these options, and have cleaned and rebuilt the solution to no avail. What am I missing?

This is the code I'm working with:

private async Task ProcessParcelFileIntoSdeTask()
 {
 CountyNameLists nameLists = new CountyNameLists();
 string message = string.Empty;
 bool processResult = false;
 var apnField = cmbAPN.SelectedValue.ToString();
 var ownerField = cmbOwner.SelectedValue.ToString();
 var selectFips = nameLists.CountyFipsCode(cmbStateList.SelectedValue.ToString(),
 cmbCountyList.SelectedValue.ToString());

 await QueuedTask.Run(() =>
 {
 using (Geodatabase geodatabase =
 new Geodatabase(new DatabaseConnectionFile(new Uri(@"PARCEL.sde"))))
 using (FeatureClass masterParcels = geodatabase.OpenDataset<FeatureClass>("Parcels.DBO.Parcel_USA"))
 using (Shapefile shapefile = new Shapefile(new ShapefileConnectionPath(new Uri(ParcelPath))))
 {
 FeatureClass parcelShapes = shapefile.OpenTable(ParcelFile) as FeatureClass;

 EditOperation editOperation = new EditOperation();
 editOperation.ProgressMessage = "Inserting parcels...";
 editOperation.Callback(context =>
 {
 try
 {
 if (parcelShapes != null)
 using (RowCursor rowCursor = parcelShapes.Search(null, false))
 {
 while (rowCursor.MoveNext())
 {
 Feature feature = rowCursor.Current as Feature;
 var attributes = new Dictionary<string, object>();
 object polygon = feature.GetShape();
 
 int field = feature.FindField(apnField);
 var fips = feature.GetOriginalValue(field);
 field = feature.FindField(ownerField);
 var owner = feature.GetOriginalValue(field);
 
 attributes["SHAPE"] = polygon;
 attributes["FIPS"] = selectFips;
 attributes["APN"] = fips;
 attributes["OWNER"] = owner;
 
 //PROGRAM CRASHES HERE. WHY?
 editOperation.Create(masterParcels, attributes);
 }
 }

 MessageBox.Show("Completed", "Task Finished", MessageBoxButton.OK,
 MessageBoxImage.Exclamation);
 }
 catch (GeodatabaseException exObj)
 {
 message = exObj.Message;
 }
 }, masterParcels);

 var task = editOperation.ExecuteAsync();
 processResult = task.Result;
 
 if (!processResult)
 message = editOperation.ErrorMessage;
 }
 });

 if (!processResult)
 MessageBox.Show(message, "Parcel Insert Error", MessageBoxButton.OK, MessageBoxImage.Error);
 }
0 Kudos
1 Solution

Accepted Solutions
CharlesMacleod
Esri Regular Contributor

Hi Scott, there are two patterns available with edit operations:

First: Using specific coarse-grained methods that do very specific kinds of edits - such as Create, Clip, Cut, Modify, etc. (https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#performing-edits-with-editoperation). This is the preferred pattern.

Second: There can be cases where your data spans GIS and non-GIS data that you need to edit atomically (within a single edit operation) and for this purpose there is the edit operation Callback method. (https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#editoperation-callback)

This choice (between coarse-grained edit operation methods and the callback method) is mutually exclusive. That is, you either invoke the callback method or coarse grained operation methods (using whichever combination of Create, Modify, Cut, etc. methods are desired) but not both. So, the fix then, is to change the code to use either the callback or the create.

To use the callback approach, replace the code inside "rowCursor.MoveNext()" with a block of code that looks something like this (pulled from this snippet https://github.com/esri/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#creating-a-row). Notice use of RowBuffer.CreateRowBuffer and Table.CreateRow to do the create and not the editoperation.Create.

using (RowBuffer rowBuffer = enterpriseTable.CreateRowBuffer())           
{
    // Either the field index or the field name can be used in the indexer.
    rowBuffer[assetNameIndex] = "wMain";            
    rowBuffer["COST"] = 700;             
    rowBuffer["ACTION"] = "Open Cut";
   // subtype value for "Abandon".            
    rowBuffer[tableDefinition.GetSubtypeField()] = 3;              
    using (Row row = enterpriseTable.CreateRow(rowBuffer))             
    {               
       // To Indicate that the attribute table has to be updated.              
       context.Invalidate(row);             
     }           
}

To use editoperation.create, delete the enclosing callback statement which should leave your existing code relatively intact (from "if (parcelShapes != null) down) looking something like this (pulled from this snippet https://github.com/esri/arcgis-pro-sdk/wiki/ProSnippets-Editing#edit-operation-create-features)

//Do your loop here....
while(rowCursor.MoveNext()) {

  //then inside the loop...
  //Do a create features and set attributes
  var attributes = new Dictionary<string, object>();
  attributes.Add("SHAPE", polygon);
  attributes.Add("NAME", "Corner Market");
  attributes.Add("SIZE", 1200.5);
  attributes.Add("DESCRIPTION", "Corner Market"); 

  createFeatures.Create(featureLayer, attributes);

} //exit the loop

//Call this when you are all done with the loop
//FYI: should be no need to use the editOperation.ExecuteAsync flavor
editOperation.Execute();

Use of the editOperation.Create would be the preferred approach (unless you have non-GIS data) and it is typically an easier pattern to implement.

View solution in original post

1 Reply
CharlesMacleod
Esri Regular Contributor

Hi Scott, there are two patterns available with edit operations:

First: Using specific coarse-grained methods that do very specific kinds of edits - such as Create, Clip, Cut, Modify, etc. (https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#performing-edits-with-editoperation). This is the preferred pattern.

Second: There can be cases where your data spans GIS and non-GIS data that you need to edit atomically (within a single edit operation) and for this purpose there is the edit operation Callback method. (https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#editoperation-callback)

This choice (between coarse-grained edit operation methods and the callback method) is mutually exclusive. That is, you either invoke the callback method or coarse grained operation methods (using whichever combination of Create, Modify, Cut, etc. methods are desired) but not both. So, the fix then, is to change the code to use either the callback or the create.

To use the callback approach, replace the code inside "rowCursor.MoveNext()" with a block of code that looks something like this (pulled from this snippet https://github.com/esri/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#creating-a-row). Notice use of RowBuffer.CreateRowBuffer and Table.CreateRow to do the create and not the editoperation.Create.

using (RowBuffer rowBuffer = enterpriseTable.CreateRowBuffer())           
{
    // Either the field index or the field name can be used in the indexer.
    rowBuffer[assetNameIndex] = "wMain";            
    rowBuffer["COST"] = 700;             
    rowBuffer["ACTION"] = "Open Cut";
   // subtype value for "Abandon".            
    rowBuffer[tableDefinition.GetSubtypeField()] = 3;              
    using (Row row = enterpriseTable.CreateRow(rowBuffer))             
    {               
       // To Indicate that the attribute table has to be updated.              
       context.Invalidate(row);             
     }           
}

To use editoperation.create, delete the enclosing callback statement which should leave your existing code relatively intact (from "if (parcelShapes != null) down) looking something like this (pulled from this snippet https://github.com/esri/arcgis-pro-sdk/wiki/ProSnippets-Editing#edit-operation-create-features)

//Do your loop here....
while(rowCursor.MoveNext()) {

  //then inside the loop...
  //Do a create features and set attributes
  var attributes = new Dictionary<string, object>();
  attributes.Add("SHAPE", polygon);
  attributes.Add("NAME", "Corner Market");
  attributes.Add("SIZE", 1200.5);
  attributes.Add("DESCRIPTION", "Corner Market"); 

  createFeatures.Create(featureLayer, attributes);

} //exit the loop

//Call this when you are all done with the loop
//FYI: should be no need to use the editOperation.ExecuteAsync flavor
editOperation.Execute();

Use of the editOperation.Create would be the preferred approach (unless you have non-GIS data) and it is typically an easier pattern to implement.