Bug in Modifying Feature?

936
23
Jump to solution
09-23-2019 01:59 PM
SusanFarley
New Contributor III

I have two Node layers in my map with the second layer being a copy of the first. I am enabling users to merge similar nodes to help clean up data, but all alterations are done on the copy layer in case the user later decides those nodes shouldn't be merged. So in my code I have:

//MergeRow is the new row and SelectedNodes is the list of rows to be deleted

public async Task<bool> MergeNodes(DataRow MergedRow, List<DataRow> SelectedNodes) {

      var modifyFeature = new EditOperation();

      modifyFeature.Name = "Merged Nodes";

      //Other stuff

      modifyFeature.Delete(MergeNodeLayer, Int64.Parse(SelectedNodes[0][oidNum].ToString()));

      modifyFeature.Execute();

     return true;

}

Even though I pass in the MergeNodeLayer, it deletes the node from both the control layer and the new layer. Is this a bug with delete or am I doing something wrong? The nodes on both layers have the same oids since it is a direct copy so it is deleting the correct one from each layer, but it should only be deleting the one for the layer I passed in.

Thank you,

Susan

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
SeanJones
Esri Regular Contributor

Hi Susan,

To get the underlying featureclass path from a feature layer you'll have to concatenate the datastore path and the featureclass name. You can then feed this into the "mva" then into the geoprocessing tool. Note that if the featureclass was in a featuredataset in the datastore you would include that in the path too (determined from featureclass.GetFeatureDataset()).

Here's an example

      QueuedTask.Run(async () =>
      {
        //find hydrant layer
        var hydLayer = MapView.Active.Map.FindLayers("Hydrant").FirstOrDefault() as FeatureLayer;

        //get the underlying featureclass path for the layer
        var hydClass = hydLayer.GetFeatureClass();

        //get the datastore for the featureclass
        var hydStore = hydClass.GetDatastore();

        //concat hydrant path (datastore and featureclass name)
        var hydPath = hydStore.GetPath().AbsolutePath + @"/" + hydClass.GetName();

        //make the value array and pass to the GP tool
        var mva = Geoprocessing.MakeValueArray(@hydPath, $@"{hydPath}2");
        await Geoprocessing.ExecuteToolAsync("Copy_management", mva);
      });

View solution in original post

0 Kudos
23 Replies
SeanJones
Esri Regular Contributor

Susan,

It sounds like both layers in the map may be pointing to the same feature class. You can check this under the layer properties source tab for each.

How did you copy the layer?

0 Kudos
SusanFarley
New Contributor III

await QueuedTask.Run(() => {

   if (LayerFactory.Instance.CanCopyLayer(frmLayer)) {

      var newLayer = LayerFactor.Instance.CopyLayer(fmLayer, MapView.Active.Map);

      newLayer.SetName (String.Format("{0}_Copy", frmLayer.Name)

   }

How do I make it create a copy of the featureclass as well?

Thank you,

Susan

0 Kudos
SeanJones
Esri Regular Contributor

Susan,

The easiest way is to use the geoprocessing copy features tool.

      var mva = Geoprocessing.MakeValueArray(@"Hydrant", @"D:\arcgis\ArcTutor\Editing\Zion.gdb\hydrant2");
      Geoprocessing.ExecuteToolAsync("CopyFeatures_management", mva);

This will copy selected features from the input layer (or all if none are selected) into the new feature class and add a new layer to the current map. You wont need to copy the layer with the LayerFactory.

0 Kudos
SusanFarley
New Contributor III

I'm guessing the C# version of that is:

foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer

{

      string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);

      string pathToFeature = $@"{gdbPath}\{newLayerName}"; 

      

      List<object> args = new List<object>() { gdbPath, newLayerName, featType.ToString(), "",

               hasMeasure, "DISABLED"};

      var res = await Geoprocessing.ExecuteToolAsync("management.CreateFeatureClass",

               Geoprocessing.MakeValueArray(args.ToArray()));

      await QueuedTask.Run(() => {

            var mva =  Geoprocessing.MakeValueArray(fmLayer, pathToFeature );

            Geoprocessing.ExecuteToolAsync("management.CopyFeatures", mva);

      }

}

Two questions:

  1. Is there a faster way to accomplish this? For two small layers (only 8270 nodes), this takes 1 minute and 24 seconds. The 1:24 is for copying both layers.
  2. On the new copies of the layers, it always seems to remove the first column of the attribute table (be it FID or Object_ID), replace it with Object_Id, but restart the numbering so that it is different than the original layer. Is there a way to prevent this? The user is looking or nodes and links in the "original layers" to merge in the "copied layers" so this causes an issue since

               var modifyInspector = new Inspector(true);

               modifyInspector.Load( MergeNodeLayer, refId); // this looks at the first column data and, with it being

                                                                //renumbered, will not edit the same node selected from the first layer as in the

                                                                //merge layer.

Example:

Original Layer 

      FID   Shape   Name   Type

      0        ....         Street   PolyLine

      1        ....         Road    PolyLine

Copied Layer

      OBJECTID   Shape   Name   Type

      1                    ....         Street   PolyLine

      2                    ....         Road    PolyLine

0 Kudos
SeanJones
Esri Regular Contributor

I hadn't considered copyfeatures re-initializing the object ids, but that makes sense since the input can be a layer. Surprisingly it also happens if you specify the featureclass as the input.

Two alternatives. Use the geoprocessing copy tool instead, which only takes featureclasses as input. This will preserve the object ids and should be faster too as it doesn't interrogate the layer.

      var mva = Geoprocessing.MakeValueArray(@"D:\arcgis\ArcTutor\Editing\Zion.gdb\Hydrant", @"D:\arcgis\ArcTutor\Editing\Zion.gdb\hydrant2");
      Geoprocessing.ExecuteToolAsync("Copy_management", mva);

The featureclass to featureclass tool is the other option but I haven't tried that.

There's no SDK API calls to copy featureclasses apart from going through the geoprocessing tools as the UI does.

0 Kudos
SusanFarley
New Contributor III

I changed my code to (I'm guessing C# translation of your code above):

      

foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer

{

      string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);

      string pathToFeature = $@"{gdbPath}\{newLayerName}"; 

      string pathFromFeature = $@"{gdbPath}\{frmLayer.Name}"; 

      var mva =  Geoprocessing.MakeValueArray(pathFromFeature , pathToFeature );

       var res = await Geoprocessing.ExecuteToolAsync("management.Copy", mva);

}

And it does nothing so I'm guessing I am doing something wrong. Any ideas what?

Thank you,

Susan

0 Kudos
SeanJones
Esri Regular Contributor

Hmm, it looks reasonable. The syntax for the GP tool name ("management.Copy" or ""Copy_managment") will work either way so thats not the issue.

Make sure the pathFromFeature and pathToFeature strings make sense for a featureclass and you could also try those manually in the geoprocessing copy tool to see if it works there. 

Your using the layer name as the feature class input which may not always be the same, particularly if the layer name has a space, the corresponding featureclass name wont.

Lastly, check the res variable (an IGPResult) to see the error message.

0 Kudos
SusanFarley
New Contributor III

The problem is that I was trying to Copy the FeatureLayer and that doesn't work with Copy. Do you know how I can get the Feature Dataset from the Feature Layer?

Thank you,

Susan

0 Kudos
SusanFarley
New Contributor III

I'm not sure if this is correct, but I have been trying this which is also not working.

foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer

{

      string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);

      string pathToFeature = $@"{gdbPath}\{newLayerName}"; 

      string pathFromFeature = $@"{gdbPath}\{frmLayer.Name}"; 

      await QueuedTask.Run(() =>

         {

            using (Table tbl = fmLayer.GetTable())

               {                  

                  var mva =  Geoprocessing.MakeValueArray(tbl, pathToFeature );

                  var res = await Geoprocessing.ExecuteToolAsync("management.Copy", mva);

                }

          }

}

res.Exception is null, res.Status = WaitingToRun, and res.Result = null.

I noticed that mva contains only strings when it is sent to Copy_management. Do you know how I correct this?

Thank you,

Susan

0 Kudos