Preserve GlobalIDs with arcpy.da.InsertCursor

3487
7
11-23-2023 03:26 PM
EM-wsp
by
Occasional Contributor

Hi,

Is it possible to preserve the GlobalIDs using arcpy.da.InsertCursor()?

I have an SDE database, arcpy.env.preserveGlobalIds = True and when I use Append to copy the data, GlobalIDs come through and match the source datasetas they should. 

However, if I use arcpy.da.InsertCursor(), GlobalIDs get replaced with the new ones.

Does preserveGlobalIds setting work just for Append? Is it the way to make the Cursor respect this setting?

Thank you!

Tags (3)
0 Kudos
7 Replies
DanPatterson
MVP Esteemed Contributor

An overview of geoprocessing environment settings—ArcGIS Pro | Documentation

I think the operative word is "Tools".  arcpy.da is a package and has no tools associated with it.

making a copy of existing values would at least provide you with a backup.

 

Geodatabase Advanced environments
Environment Description
Preserve Global IDs

Tools that honor the Preserve Global IDs environment will reuse the Global ID values of the existing input dataset when appending rows to a target dataset.


... sort of retired...
0 Kudos
EM-wsp
by
Occasional Contributor

Hi!
Thank you  for your reply! I understand now why environmental setting is ignored by the Cursor.

But is there any way to get globalids preserved with the InsertCursor? I tried to apply UpdateCursor as well after inserting, but with no success. The tool doesn't complain or fail, it even takes some time to run, but the GlobalIDs are still new.

Since the in-built tools (Append, Copy etc) can have it preserved, the database apparently has this functionality. Can it be somehow set up in the Cursor functions?

0 Kudos
DanPatterson
MVP Esteemed Contributor

No is the short answer.  Geoprocessing Tools have environments


... sort of retired...
0 Kudos
EM-wsp
by
Occasional Contributor

Ok, thank you. At least I got it confirmed.

0 Kudos
VinceAngelo
Esri Esteemed Contributor

The long answer is that you might be able to use the fid returned by arcpy.da.InsertCursor.insertRow() to build a dictionary (lookup[fid] = old_globalid), then use the created fid in a DA UpdateCursor pass to update the uuid value:

 

updated = 0
with arcpy.da.UpdateCursor(fc,['objectid','globalid']) as cursor:
    for row in cursor:
        if row[0] in lookup:
            cursor.updateRow([row[0],lookup[row[0]])
            updated += 1
print("{:d} globalid values updated".format(updated))

 

This could only work because cursors ignore GlobalID values. I haven't tested this, but it's worth a shot.

- V

PS: Oh, and there exists a chance (however slight) that one of the new UUIDs could conflict with  a replacement GlobalID value, though it's  so slight that you probably don't need to check first (but if it does occur, then the global dictionary in memory will be lost by the error).

0 Kudos
EM-wsp
by
Occasional Contributor

Hi,

Thank you for your reply.

I had tested exactly the same approch before creating this post, and it didn't work. We can conclude that neither InsertCursor, nor UpdateCursor are able to modify GlobalIDs. 

VinceAngelo
Esri Esteemed Contributor

Okay, so I had my replica globalid population corrupted by the failure of arcpy.da.InsertCursor to honor  arcpy.env.preserveGlobalIds, and a search turned this up, so I needed to engineer a solution.

If there's only a few features, and a reliable key column, you could use an array to store up key_col(s),globalid list of lists to issue an UPDATE via an arcpy.ArcSDESQLExecute cursor but I have widely disparate row counts in several score of tables, and sending 30M UPDATE commands is not the most efficient way to attack this problem (at only 6ms per UPDATE that's 50 hours wasted).

What I've settled on is populating parallel tables with the primary key column(s) plus globalid as a VARCHAR(38) column, then running a single update:

UPDATE schema.tablename_t1 t
SET    globalid = vt.globalid
FROM (
    SELECT t1.objectid,g1.globalid
    FROM   schema.tablename_g1 g1
    JOIN   schema.tablename_t1 t1 USING (keycolumns)
) vt
WHERE  t.objectid = vt.objectid

Notes:

  • This won't work with versioned tables (I need to populate these tables before enabling versioning, so I'm good)
  • You need to use an arcpy.da.Editor to populate the tables in parallel (two open DA cursors on the same connection won't work without it)
  • I drive the inner virtual table query from the G1 to the T1, because then I don't have to index both tables, just T1 (which I need to index anyway).
  • Don't forget to TRUNCATE the g1 table contents or DROP a standalone temp table after the UPDATE.

- V

0 Kudos