1

I have a layer with over 250,000+ features, and I want to update all the attribute data using ArcObjects and C#. I have written the code below and it takes around 3 hours to perform the update. Can you suggest whether the code below is efficient enough and any suggestion regarding the delta tables please?

public void updateWithCursor(IWorkspace workspace, IFeatureClass featureClass, List<Update> updateList)
    {
        using (ComReleaser comReleaser = new ComReleaser())
        {
            IWorkspaceEdit workspaceEdit = (IWorkspaceEdit)workspace;

            // Start an edit session
            workspaceEdit.StartEditing(false);

            // Start an edit operation
            workspaceEdit.StartEditOperation();
            // Use IFeatureClass.Search to create a search cursor.
            IFeatureCursor searchCursor = featureClass.Search(null, false);
            comReleaser.ManageLifetime(searchCursor);

            // Find the positions of the fields used to get and set values.
            int idIndex = featureClass.FindField("ID");
            int serialIndex = featureClass.FindField("SERIAL");
            int cityIndex = featureClass.FindField("CITY");
            int updateDateIndex = featureClass.FindField("UPDATEDATE");

            int counter = 0;
            IFeature feature = null;
            while ((feature = searchCursor.NextFeature()) != null)
            {
                string searchValue = feature.get_Value(idIndex).ToString();

                if (searchValue != "")
                {
                    Update upd = updateList.SingleOrDefault(x => x.id == searchValue);

                    if (upd != null)
                    {                            
                        feature.set_Value(serialIndex , upd.serialNo);
                        feature.set_Value(cityIndex , upd.city);
                        feature.set_Value(updateDateIndex, DateTime.Now);
                        feature.Store();
                    }
                    Console.WriteLine(counter++);
                }
            }

            workspaceEdit.StopEditOperation();

            // Stop the edit session
            workspaceEdit.StopEditing(true);
        }
    }
1
  • You should use a Dictionary instead of a List for your updates, see my answer below.
    – crmackey
    Commented Feb 17, 2018 at 15:55

2 Answers 2

1

The process you are doing should not take that long, and the bottleneck is your UpdateList. On each iteration of of your search cursor, the UpdateList is searched from the beginning until a matching ID is found. It would be much more efficient to use a HashTable or a Dictionary so you can create a lookup via the ID to update your table. From this page:

Both lists and dictionaries are used to store collections of data. The Dictionary is based on a hash table, that means it uses a hash lookup, which is a rather efficient algorithm to look up things, on the other hand, a list you have to go element by element until it finds the result from beginning to the result each time.

So what you can do is set up your UpdateList as a Dictionary where your values are a Dictionary where every entry would be:

UpdateDict[id] = valueDict //where valueDict is {"city": "Chicago", "serialNo": 100}

My C# is pretty rusty, but maybe in your search cursor you can do something like this:

while ((feature = searchCursor.NextFeature()) != null)
    {
        string searchValue = feature.get_Value(idIndex).ToString();

        if ((searchValue != "") && (UpdateDict.ContainsKey(searchValue)))
        {
            Dictionary upd = UpdateDict[searchValue];  //use this update dict instead of list

            if (upd != null)
            {                            
                feature.set_Value(serialIndex , upd["serialNo"]);
                feature.set_Value(cityIndex , upd["city"]);
                feature.set_Value(updateDateIndex, DateTime.Now);
                feature.Store();
            }
            Console.WriteLine(counter++);
        }
    }
0

I would ditch the search cursor and do something like this:

foreach(var upd in updateList)
{
    IFeature feature = featureClass.GetFeature(upd.id); 
    feature.set_Value(serialIndex , upd.serialNo);
    feature.set_Value(cityIndex , upd.city);
    feature.set_Value(updateDateIndex, DateTime.Now);
    feature.Store();
}

Now you don't have to search through updateList or put it in a hashtable.

Also, if this is a standalone program (not an Add-in) then you'll want to wrap all your ArcObjects code to run in not only the same thread, but a SingleThreadedApartment thread.

So something like this would do:

        static void Main(string[] args)
        {
            Thread t = new Thread((x) =>
                { //ArcObjects code
                });
            t.SetApartmentState(ApartmentState.STA);
            t.Start();
            t.Join();
        }

The reason is that all ArcObjects are SingleThreadedApartment [STA] COM objects. When using an STA COM object created on a different thread there is a significant delay when marshaling calls between threads. STA objects created in a MultiThreadedApartment [MTA] (which is the default for Console apps, WPF, Forms, etc.) will actually be created on a separate STA thread. This means any interaction with ArcObjects will incur the performance penalty for marshaling calls between threads. By creating an STA thread that penalty is removed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.