10

I have some Python code that is launched from within an ArcMap project. Any joins that the user may have created in the project must be removed in order for my code to run. Unfortunately, the code that removes a join… arcpy.RemoveJoin_management("layer1", "layer2")… also breaks some of the layer properties that are critical to my application (highlighted fields, read-only fields, etc).

If joins are removed by right-clicking the layer in ArcMap and choosing “Remove Joins” the layer properties are left intact.

If I can detect that a join exists from within my code, I will simply exit the code and display a message that the user must manually remove their joins before attempting to run the code. So… Can a Join be detected programmatically?

5
  • I'm a bit lost on how doing the RemoveJoin via arcpy causes problems. How does it going about ruining a read-only field? Also, does using the Remove Join tool in ArcMap cause the same issues?
    – Nathanus
    Mar 24, 2011 at 21:49
  • Maybe another way to tackle this would be to make your python code insensitive to joins?
    – Dan S.
    Mar 24, 2011 at 23:17
  • @ Nathanus - The manual Remove Join in ArcMap does not break my layer properties, the GP tool does. Here is a relevant quote from ESRI Help: "As these tools perform the actual behind-the-scenes join processing slightly differently than the Join Data dialog box, use the tools if you encounter any unexpected issues with the join functionality on that dialog box." Mar 25, 2011 at 0:37
  • @ Dan S. - I am using insert cursors and such in my code. I have no idea how I would go about making my code insensitive to joins. Mar 25, 2011 at 0:40
  • 1
    well, it was worth asking. ;) forums.esri.com/Thread.asp?c=93&f=1729&t=293173 seems to imply that you may be able to update values in a joined table by prefixing column names by the table name, though; maybe it would work across an insert too?
    – Dan S.
    Mar 25, 2011 at 1:18

3 Answers 3

8

Too bad there's not a hasJoin property on the arcpy.Layer class. I think you can test for a join by looking at field names though. Here's a simple proof of concept for data in a file geodatabase:

import arcpy, arcpy.mapping as arc

def joinCheck(lyr):
  fList = arcpy.Describe(lyr).fields
  for f in fList:
    if f.name.find(lyr.datasetName) > -1:
      return True
  return False

arcpy.env.workspace = r'<path_to_your_gdb>'
mxd = arc.MapDocument(r'<path_to_your_mxd>')
lyrs = arc.ListLayers(mxd)
for lyr in lyrs:
  # ignore group layers
  if not lyr.isGroupLayer:
    hasJoin = joinCheck(lyr)
    if hasJoin:
      print '\nFound a join: %s.' % lyr.datasetName
    else:
      print '\nNo join found on %s.' % lyr.datasetName
4
  • This looks promising! I don't understand the meat of what it is doing: "if f.name.find(lyr.datasetName) > -1:" but I will try it in a few days and report back (I'm about to get snowed in & lose power!)... Thanks! Mar 25, 2011 at 0:55
  • Glad to help. Check out the built in find method for python strings: docs.python.org/library/string.html and also the doc for arcpy field objects: help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/Field/… I'd say give this code a shot with your data and see if it works. Mar 25, 2011 at 4:25
  • 2
    I ended up using a function very similar to this one and it works great... For each layer in my document, I loop through the fields list and use Python to determine whether there is a "dot" in the field name. Mar 29, 2011 at 2:26
  • The "dot" in the field name approach is a choice with arcpy.mp (pro) module as there is no datasetName property available for Layer May 2, 2020 at 5:29
1

I think you will find that there is no bulletproof way to do this with GP objects, you'll need to use ArcObjects and comtypes. Here's some discussion from the ESRI forums on the difficulties in checking for joins with the standard GP tools/objects: https://geonet.esri.com/thread/20317

1
  • ArcObjects and comtypes aren't going to be the solution for this project, they are foreign to me and this project is due yesterday. Thanks for pointing me to that forum thread! I'm going to try the idea presented there: "...check whether any of the fieldname.split(".) would result in 2 parts of which the first would be the Join table!" Mar 25, 2011 at 0:52
0

In answer to comment above, arcpy.RemoveJoin_management raises an exception if there are no joins on the table. Also, ArcPy does not support update cursors on joined tables, even if the field being updated is in the base table. However, you can put arcpy.RemoveJoin_management inside a try block with no action on the exception if there are no joins.

A workaround to how to do an update from a field in a joined table is to create a dictionary from the the table that would be joined and use it as a lookup for the value of the non-key fields using the key field.

In this example code fragment, I have a table named LOCNAME which has a unique key field named "Loc_name" (which identifies a particular level of a composite address locator) and a non-key field "Descript" which gives a text description of the particular level.

I have already added the "Descript" field to the attribute table of a geocoded address list thisLayer containing the field "Loc_name" that identifies which level that particular address was geocoded, and I want to update the value of "Descript" using the corresponding value from the LOCNAME table.

try:
  arcpy.RemoveJoin_management(thisLayer)
except:
  pass

thisLayerDataSource = thisLayer.dataSource
theDescriptDict = {}    
theLOCNAMECursor = arcpy.SearchCursor(theLOCNAMEDataSource)
for theLoc_name in theLOCNAMECursor:
  theDescriptDict[theLoc_name.getValue("Loc_name")] = \     
    theLoc_name.getValue("Descript")

rows = arcpy.UpdateCursor(thisLayerDataSource, ["Descript", "CTCERTCODE", \ 
  "CTCERTDESC", "SortMe"])
for row in rows:
  thisLocName = row.getValue("Loc_name")
  if ((thisLocName != ' ') and (thisLocName != '')):
    thisDescript = theDescriptDict[thisLocName]
    row.setValue("Descript", str(thisDescript))

If you have several fields in the second table, just make a dictionary for each field (still keyed by the same unique field) and using the UpdateCursor on the primary table, use row.setValue statements for each field.

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.