How do you write to a feature layer's field?

797
6
Jump to solution
03-22-2023 11:41 AM
tzz_12
by
New Contributor III

I know how to create a new field in an existing feature class, but if I have a list of calculated outputs, how do I write those outputs in the new fields? Can I use the index of the feature class's table to write the values row by row using the common index? Is there a community sample that you recommend? 

Thanks everyone!

0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor

Using a cursor, this is how I calculated the field "PS_Count" in the FeatureClass "featureClass" to 1.

QueryFilter queryFilter = new() { WhereClause = "1=1" };
EditOperation editOperation = new();
await QueuedTask.Run(() =>
{
  using RowCursor rowCursor = featureClass.Search(queryFilter, false);
  while (rowCursor.MoveNext())
  {
    using Row record = rowCursor.Current;
    editOperation.Modify(record, "PS_Count", 1);
  }
});
if (!await editOperation.ExecuteAsync()) MessageBox.Show(editOperation.ErrorMessage);

 

The other way you can do this is with the GeoProcessing Tool

IGPResult GPResult = await CalculateFeatures(featureClass, "PS_Count", "1", "ARCADE", null, "LONG", GPExecuteToolFlags.AddToHistory);
if (GPResult.IsFailed)
{
  MessageBox.Show("Failed to calculate Count field");
}

public static async Task<IGPResult> CalculateFeatures(FeatureClass InFC, string FieldName, string exp, string exp_type, string code_block, string fieldtype, GPExecuteToolFlags flags)
{
  List<object> arguments = new() {
    InFC, //In Table
    FieldName, //Field
    exp, //Expression
    exp_type, //Expression Type
    code_block, //Code Block,
    fieldtype, //Field Type
  };
  IGPResult result = await Geoprocessing.ExecuteToolAsync("management.CalculateField", Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, flags);
  return result;
}

 

View solution in original post

0 Kudos
6 Replies
KenBuja
MVP Esteemed Contributor

Using a cursor, this is how I calculated the field "PS_Count" in the FeatureClass "featureClass" to 1.

QueryFilter queryFilter = new() { WhereClause = "1=1" };
EditOperation editOperation = new();
await QueuedTask.Run(() =>
{
  using RowCursor rowCursor = featureClass.Search(queryFilter, false);
  while (rowCursor.MoveNext())
  {
    using Row record = rowCursor.Current;
    editOperation.Modify(record, "PS_Count", 1);
  }
});
if (!await editOperation.ExecuteAsync()) MessageBox.Show(editOperation.ErrorMessage);

 

The other way you can do this is with the GeoProcessing Tool

IGPResult GPResult = await CalculateFeatures(featureClass, "PS_Count", "1", "ARCADE", null, "LONG", GPExecuteToolFlags.AddToHistory);
if (GPResult.IsFailed)
{
  MessageBox.Show("Failed to calculate Count field");
}

public static async Task<IGPResult> CalculateFeatures(FeatureClass InFC, string FieldName, string exp, string exp_type, string code_block, string fieldtype, GPExecuteToolFlags flags)
{
  List<object> arguments = new() {
    InFC, //In Table
    FieldName, //Field
    exp, //Expression
    exp_type, //Expression Type
    code_block, //Code Block,
    fieldtype, //Field Type
  };
  IGPResult result = await Geoprocessing.ExecuteToolAsync("management.CalculateField", Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, flags);
  return result;
}

 

0 Kudos
Aashis
by Esri Contributor
Esri Contributor

The DDL API can create a new field to store calculated results, "CalculateResults," in an existing feature class.

Then, iterate rows and set the calculated value on the new field. For the CoreHost application, use geodatabase.ApplyEdits to update the row with a calculated value as 

 

using (FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>(featureClassName))
{
  geodatabase.ApplyEdits(() =>
  {
   // Search and iterate all rows
	using (RowCursor rowCursor = featureClass.Search(null, false))
	{
	  while (rowCursor.MoveNext())
	  {
		using (Row row = rowCursor.Current)
		{
		  // Set results to the new field
		  row["CalculateResults"] = "SetYourValue"
		  row.Store();
		}
	  }
	}
  });
}

 

 

0 Kudos
tzz_12
by
New Contributor III

Hi Aashis, 

Thanks for your help! Can I get your feedback on the two error messages I received using your method.  When I tried to set the row field to a OutputList, I received the following error: "The value type is incompatible". When I set the row field with just a single value to see if it works,  "row.Store()" had an error message that it cannot be stored in a edit session. Please see my script below. I appreciate your help! Thanks!

  await QueuedTask.Run(() =>
                {
                    using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(outPath))))
                    {
                        using (FeatureClass FC = geodatabase.OpenDataset<FeatureClass>("FC_name"))
                        {
                            geodatabase.ApplyEdits(() =>
                            {
                                // Search and iterate all rows
                                using (RowCursor rowCursor = FC.Search())
                                {
                                    while (rowCursor.MoveNext())
                                    {
                                        using (Row row = rowCursor.Current)
                                        {
                                            // Set results to the new field
                                            //incompatible type error 
                                            row["SD"] = OutputList; 
                                            row.Store(); //edit mode error
                                        }
                                    }
                                }

                            });
                        }
                    }
                });

 

0 Kudos
Aashis
by Esri Contributor
Esri Contributor

See Wolf's comment below and also set the recycling cursor to false.

using (RowCursor rowCursor = featureClass.Search(null, false))

 

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

The error message "The value type is incompatible" is referring to the data type of the database column and the datatype of the OutputList variable.  Your code snippet doesn't show what types we are dealing with, but in general when you update column values in a database table (or feature class) you can only assign the appropriate matching datatype.   Take for example this table:

Wolf_0-1679578647443.png

I have the DataTypes of Geometry, Double and Text.   So when i update those column values i can only assign a geometry (here even the geometry type point, line, polygon has to match) value, double value or a string value to those columns.  Judging by the name 'OutputList' you probably store some type of list of strings or numbers and there is no geodatabase column datatype that supports lists (or arrays).  You could store a short list as a comma separated list of strings in a text field, but you have to watch out for character limits on text fields. 

tzz_12
by
New Contributor III

Hi Wolf & Aashi, 

Thanks for your help! I was thinking since I have multiple new calculated result fields for each row. I can create a separate variable for each calculated values, instead of joining them together as a list. How can I create a method in C# that will output multiple values, without making it a list or tuple? 

Thanks for your help!

0 Kudos