Существует множество причин, когда необходимо восстановить источники данных или перенаправить их в другие места. В виде Каталог в ArcGIS Pro есть возможности для обновления источников данных. Но внесение этих изменений вручную в каждую карту или проект может показаться непосильным трудом. В среде разработки скриптов arcpy.mp доступны методы, которые делают возможным автоматизацию внесения этих изменений без необходимости открытия проекта. Можно управлять обновлением источников данных для отдельных слоев или таблиц, или обновлять все слои или таблицы одновременно в одной общей рабочей области за один раз.
Следующие составляющие используются в рабочих процессах изменения источника данных:
- Свойство connectionProperties доступно для классов Layer и Table.
- Метод updateConnectionProperties доступен для классов ArcGISProject, Layer, LayerFile, Map и Table.
Использование функции updateConnectionProperties
Функцию updateConnectionProperties можно рассматривать как функцию поиска и замены, с помощью которой вы заменяете параметр current_connection_info параметром new_connection_info. Этими параметрами могут быть либо полный путь к рабочей области, частичная строка, словарь, содержащий свойства соединения, частичный словарь, который определяет конкретные ключи, либо путь к файлу подключения к базе данных (.sde).
Подсказка:
При обновлении источников данных для слоев многопользовательской базы геоданных файлы подключения к базе данных могут использоваться в параметрах current_connection_info и new_connection_info, например:
aprx.updateConnectionProperties(r'C:\DBConnections\TestGDB.sde',
r'C:\DBConnections\ProductionGDB.sde')
Свойство auto_update_joins_and_relates позволяет вам контролировать, должны ли быть обновлены соединения и связи, связанные со слоем или таблицей. Значение по умолчанию установлено на True. Могут быть варианты, особенно при обновлении всех источников данных на уровне проекта, при которых может потребоваться оставить эти связанные источники без обновления. В этом случае установите параметр False.
По умолчанию, метод updateConnectionProperties обновляет источник данных, только если new_connection_info является допустимым источником данных. Если параметру validate задано значение False, то источник данных устанавливается в данное местоположение не зависимо, существует он или нет. Это может оказаться полезным в тех сценариях, в которых необходимо обновить источники данных до создания самих данных. В этих случаях данные являются поврежденными в связанных картах.
Как изменить набор данных слоя на класс пространственных объектов с другим именем, см. Использование словаря connectionProperties ниже.
Вот несколько примеров:
Следующий скрипт изменяет полный путь к источнику данных файловой базы геоданных для всех слоёв и таблиц в проекте. В этом примере папка была переименована, и все векторные данные были перемещены в это новое местоположение:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties(r'C:\Projects\YosemiteNP\Data\Yosemite.gdb', r'C:\Projects\YosemiteNP\Vector_Data\Yosemite.gdb') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Следующий пример очень похож на приведённый выше, но для замены источников данных используются строки частичных путей. Убедитесь, что при использовании частичной строки она не повторяется в пути несколько раз. Ожидаемые результаты могут быть не получены.
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties('Data','Vector_Data') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
В следующем примере заменяется подключение персональной базы геоданных на подключение файловой базы геоданных с использованием частичного пути для всех слоев и таблиц на карте:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') m = aprx.listMaps("Yose*")[0] m.updateConnectionProperties('Background.mdb', 'Background_fGDB.gdb') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Следующий пример ссылается на слой на карте и использует эти свойства подключения для обновления свойств подключения для того же слоя в файле слоя, который не был обновлен с новым источником данных:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') m = aprx.listMaps('Yose*')[0] lyr = m.listLayers('Ranger Stations')[0] lyrFile = arcpy.mp.LayerFile(r'C:\Projects\YosemiteNP\LYRXs\Yosemite\OperationalLayers.lyrx') for l in lyrFile.listLayers(): if l.name == 'Ranger Stations': l.updateConnectionProperties(l.connectionProperties, lyr.connectionProperties) lyrFile.save()
Вот несколько примеров обновления источников данных для слоев многопользовательской базы геоданных:
В следующем примере подключение к файловой базе геоданных заменяется на путь к файлу подключения (.sde) многопользовательской базы геоданных для всех слоев и таблиц в проекте:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties(r'C:\Projects\YosemiteNP\Vector_Data\Yosemite.gdb', r'C:\Projects\YosemiteNP\DBConnections\Server.sde') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
В следующем примере свойства подключения из файла подключения многопользовательской базы геоданных в параметре current_connection_info заменяются новым файлом подключения многопользовательской базы геоданных в параметре new_connection_info:
Примечание:
Указанный в параметре current_connection_info файл подключения многопользовательской базы данных не обязательно должен быть фактическим файлом подключения, используемым для создания слоя. Скорее, свойства подключения, содержащиеся в файле подключения, будут использоваться в функции поиска и замены updateConnectionProperties.
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties(r'C:\Projects\YosemiteNP\DBConnections\TestGDB.sde', r'C:\Projects\YosemiteNP\DBConnections\ProductionGDB.sde') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
В следующем примере файл подключения многопользовательской базы геоданных заменяется на путь к файловой базе геоданных для всех слоев и таблиц в проекте:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties(r'C:\Projects\YosemiteNP\DBConnections\Server.sde', r'C:\Projects\YosemiteNP\Local_Data\YosemiteLocal.gdb') aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Подсказка:
Если при замене параметра current_connection_info на параметр new_connection_info в функции updateConnectionProperties совпадений не найдено, ваш скрипт может завершиться, но ничего не будет обновлено.Использование функции connectionProperties
Изменение connectionProperties для обновления источников данных требует, чтобы вы работали со словарём свойств подключения. Возвращаемый словарь варьируется в зависимости от того, является ли он файловой рабочей областью или подключением к базе данных, или имеют ли слой или таблица ассоциированные соединения или связи. Из-за этой изменчивости важно понимать различные типы свойств подключений и то, как следует ориентировать словари для внесения соответствующих изменений. Например, слой с соединением или связью, возвращает совсем другой результат, чем тот же слой без соединения или связи. Подход, используемый при обновлении словарей свойств соединения, состоит в том, чтобы ссылаться и извлекать словарь из слоя или таблицы, вносить в него необходимые изменения, а затем применять измененный словарь обратно к слою или таблице, которые вы хотите обновить, используя метод updateConnectionProperties.
Хороший способ отобразить структуру словаря – использовать функцию pprint Python. import arcpy, pprint
p = arcpy.mp.ArcGISProject('current')
m = p.listMaps()[0]
l = m.listLayers()[0]
pprint.pprint(l.connectionProperties)
Например, файловый источник данных без соединений или связей будет выглядеть следующим образом:
{'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\Yosemite.gdb'},
'dataset': 'RangerStations',
'workspace_factory': 'File Geodatabase'}
Указанный выше пример является самой базовой структурой. Возвращается словарь с тремя ключами. Значением для ключа connection_info является другой словарь, который содержит путь к database.
Одним из наиболее распространенных вариантов использования словаря connectionProperties является замена набора данных слоя на класс пространственных объектов с другим именем. Вот несколько примеров:
Следующий пример обновляет имя набора данных источников данных с RangerStations на RangerStationsNew. От также изменяет базу данных с Yosemite.gdb на YosemiteNew.gdb.
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') lyr = aprx.listMaps("Main*").listLayers("Ranger Stations")[0] find_dict = {'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\Yosemite.gdb'}, 'dataset': 'RangerStations', 'workspace_factory': 'File Geodatabase'} replace_dict = {'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\YosemiteNew.gdb'}, 'dataset': 'RangerStationsNew', 'workspace_factory': 'File Geodatabase'} lyr.updateConnectionProperties(find_dict, replace_dict) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Приведенный выше скрипт также можно переписать следующим образом:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') lyr = aprx.listMaps("Main*").listLayers("Ranger Stations")[0] cp = lyr.connectionProperties cp['connection_info']['database'] = 'C:\\Projects\\YosemiteNP\\Data\\YosemiteNew.gdb' cp['dataset'] = 'RangerStationsNew' lyr.updateConnectionProperties(lyr.connectionProperties, cp) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Частичный словарь также может быть использован в методе updateConnectionProperties, как видно из приведенного ниже примера.
В следующем примере обновляется имя набора данных источника данных с PtsInterest на PointsOfInterest для слоев в проекте. Этот пример не меняет базу геоданных, в которой находится класс пространственных объектов. Скорее, он обновляет слои, чтобы они указывали на другой класс пространственных объектов в той же базе геоданных:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') aprx.updateConnectionProperties({'dataset': 'PtsInterest'}, {'dataset': 'PointsOfInterest'}) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Словарь connectionProperties также можно использовать для обновления файловых источников данных, таких как шейп-файлы, растровые файлы и т.д. В следующем примере изменяется источник данных слоя, чтобы он указывал на новый шейп-файл в другой папке.
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') lyr = aprx.listMaps('Main*').listLayers('RoadsShp')[0] cp = lyr.connectionProperties cp['connection_info']['database'] = 'C:\\Projects\\YosemiteNP\\Data_New' cp['dataset'] = 'NewRoads.shp' lyr.updateConnectionProperties(lyr.connectionProperties, cp) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Использование словаря connectionProperties с данными многопользовательской базы геоданных
Ниже приводится пример словаря connectionProperties источника данных многопользовательской базы геоданных для слоя:
{'connection_info': {'authentication_mode': 'OSA',
'database': 'TestDB',
'db_connection_properties': 'TestServer',
'dbclient': 'sqlserver',
'instance': 'sde:sqlserver:TestServer',
'password': '*********',
'server': 'TestServer',
'user': 'User',
'version': 'sde.DEFAULT'},
'dataset': 'TestDB.USER.RangerStations',
'workspace_factory': 'SDE'}
Такие же три ключа возвращаются для слоя файловой базы геоданных, но в этом случае значение connection_info – словарь с большим числом свойств подключения к базе данных. Любое из этих свойств может быть изменено.
В следующем примере изменяются экземпляр и база данных многопользовательской базы геоданных для всех слоев проекта. В этом примере многопользовательская база геоданных использует аутентификацию операционной системы, а имя базы данных такое же. Если имена пользователей и пароли совпадают, экземпляр и сервер можно изменить, не зная учетных данных слоев в проекте и не создавая новые файлы подключений многопользовательской базы геоданных.import arcpy
aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx')
find_dict = {'connection_info': {'db_connection_properties': 'TestServer',
'instance': 'sde:sqlserver:TestServer',
'server': 'TestServer'}}
replace_dict = {'connection_info': {'db_connection_properties': 'ProdServer',
'instance': 'sde:sqlserver:ProdServer',
'server': 'ProdServer'}}
aprx.updateConnectionProperties(find_dict, replace_dict)
aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Использование словаря connectionProperties с соединениями
Словарь connectionProperties также покажет свойства любых объединений, которые присутствуют на слое. Любое из этих свойств может быть изменено.
В приведенном ниже примере показан словарь connectionProperties источника данных на основе файлов с одним соединением:
{'cardinality': 'one_to_many',
'destination': {'connection_info': {'database': 'C:\\Projects\\FGDB.gdb'},
'dataset': 'tabular_eco',
'workspace_factory': 'File Geodatabase'},
'foreign_key': 'ECO_CODE',
'join_forward': False,
'join_type': 'left_outer_join',
'primary_key': 'CODE',
'source': {'connection_info': {'database': 'C:\\Projects\\FGDB.gdb'},
'dataset': 'mex_eco',
'workspace_factory': 'File Geodatabase'}}
В этом примере показан словарь connectionProperties источника данных на основе файлов с двумя соединениями:
{'cardinality': 'one_to_many',
'destination': {'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\BackgroundData.gdb'},
'dataset': 'census2000',
'workspace_factory': 'File Geodatabase'},
'foreign_key': 'State_Polygons.State_Name',
'join_forward': False,
'join_type': 'left_outer_join',
'primary_key': 'STATE_NAME',
'source': {'cardinality': 'one_to_many',
'destination': {'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\BackgroundData.gdb'},
'dataset': 'census2010',
'workspace_factory': 'File Geodatabase'},
'foreign_key': 'State_Name',
'join_forward': False,
'join_type': 'left_outer_join',
'primary_key': 'STATE_NAME',
'source': {'connection_info': {'database': 'C:\\Projects\\YosemiteNP\\Data\\BackgroundData.gdb'},
'dataset': 'State_Polygons',
'workspace_factory': 'File Geodatabase'}}}
Когда соединения связаны со слоем или таблицей, структура словаря connectionProperties изменяется. У вас больше нет тех же трех ключей корневого уровня, как вы видели в предыдущих примерах. Чтобы понять, почему это отличается, следует изучить то, как сохраняются соединения. Соединения являются вложенными. Например, если таблица 1 и таблица 2 соединены со слоем, таблица 1 соединена со слоем, а таблица 2 соединена с комбинацией слоя и таблицы 1. Словарь корневого уровня сначала описывает второе соединение. Для второго source соединения, можно отслеживать связь с исходным слоем и таблицей один.
Вот несколько примеров использования словаря connectionProperties с соединениями:
В следующем примере изменяется внешний ключ соединения для определенного слоя:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\Mexico\MexicoEcology.aprx') mexLyr = aprx.listMaps('Layers')[0].listLayers('mex_eco')[0] conProps = mexLyr.connectionProperties conProps['foreign_key'] = 'ECO_CODE_NEW' mexLyr.updateConnectionProperties(mexLyr.connectionProperties, conProps) aprx.saveACopy(r"C:\Projects\Mexico\MexicoEcologyNew.aprx")
Частичный словарь может также использоваться в методе updateConnectionProperties. В следующем примере изменяются свойства соединения для всех слоев в проекте, которые используют указанный внешний ключ:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\Mexico\MexicoEcology.aprx') aprx.updateConnectionProperties({'foreign_key': 'ECO_CODE'}, {'foreign_key': 'ECO_CODE_NEW'}) aprx.saveACopy(r"C:\Projects\Mexico\MexicoEcologyNew.aprx")
В следующем примере изменяется база данных и набор данных источника для основного слоя, к которому присоединяются обе таблицы, без изменения информации о подключении для соединений:
import arcpy aprx = arcpy.mp.ArcGISProject(r'C:\Projects\YosemiteNP\Yosemite.aprx') lyr = aprx.listMaps("Main*").listLayers("State_Polygons")[0] conProp = lyr.connectionProperties conProp['source']['source']['connection_info']['database'] = 'C:\\Projects\\YosemiteNP\\Vector_Data\\Census.gdb' conProp['source']['source']['dataset'] = 'States' lyr.updateConnectionProperties(lyr.connectionProperties, conProp) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
В следующем примере будет создан список соединений всех соединений на всех слоях карты. В этом примере используется логика рекурсивной функции Python для обработки слоев, которые не имеют ни одного соединения, или любого количества соединений:
import arcpy def ListJoinsConProp(cp, join_count=0): if 'source' in cp: if 'destination' in cp: print(' '*6, 'Join Properties:') print(' '*9, cp['destination']['connection_info']) print(' '*9, cp['destination']['dataset']) join_count += 1 return ListJoinsConProp(cp['source'], join_count) else: if join_count == 0: print(' '*6, '- no join') aprx = arcpy.mp.ArcGISProject(r"C:\Projects\Mexico\MexicoEcology.aprx") m = aprx.listMaps()[0] for lyr in m.listLayers(): print(f"LAYER: {lyr.name}") if lyr.supports("dataSource"): cp = lyr.connectionProperties if cp is not None: ListJoinsConProp(cp)
В следующем примере будут отображаться свойства подключения слоев на карте. Аналогично примеру выше, в этом примере также используется логика рекурсивной функции Python для обработки слоев, которые не имеют ни одного соединения, или любого количества соединений:
import arcpy def ConPropsWithJoins(cp): if 'source' in cp: return ConPropsWithJoins(cp['source']) else: print(' '*6, 'database:', cp['connection_info']['database']) print(' '*6, 'dataset:', cp['dataset']) print(' '*6, 'workspace_factory:', cp['workspace_factory']) aprx = arcpy.mp.ArcGISProject(r"C:\Projects\Mexico\MexicoEcology.aprx") m = aprx.listMaps()[0] for lyr in m.listLayers(): print(f"LAYER: {lyr.name}") if lyr.supports("dataSource"): cp = lyr.connectionProperties if cp is not None: ConPropsWithJoins(cp)
Обновление источников данных через CIM
Начиная с версии ArcGIS Pro 2.4, разработчики Python получили расширенный доступ к Картографической информационной модели (CIM) и смогут использовать намного больше настроек, свойств и возможностей, содержащихся в документе или проекте. Это может быть полезно при обновлении рабочих процессов источника данных. Более подробную информацию смотрите в разделах:
Если с помощью функции updateConnectionProperties сложно выполнить конкретный рабочий процесс источника данных, можно изменить структуру CIM слоя. В разделе Доступ к Python CIM описывается структура JSON объектной модели CIM. Понимание этой структуры позволит вам обновить CIM слоя.
Например, ниже приведено представление JSON источника данных слоя САПР. JSON ниже не является полной структурой CIM слоя. Скорее, это моментальный снимок, показывающий только узел dataConnection."dataConnection" : {
"type" : "CIMFeatureDatasetDataConnection",
"featureDataset" : "parcels.dwg",
"workspaceConnectionString" : "DATABASE=C:\\Projects\YosemiteNP\\CAD",
"workspaceFactory" : "Cad",
"dataset" : "Polyline",
"datasetType" : "esriDTFeatureClass"
}
Ниже приведены некоторые примеры использования CIM для обновления источников данных:
Следующий пример ссылается на слой САПР на карте. Затем он обновит слой, чтобы указать на новый файл САПР. Скрипт предполагает, что новый файл САПР находится в той же папке, что и предыдущий файл САПР.
Примечание:
Обновление источника данных для слоев САПР для указания на новый файл САПР требует изменения CIM. Однако просто изменить папку, в которой находится файл САПР, можно с помощью функции updateConnectionProperties.
import arcpy aprx = arcpy.mp.ArcGISProject(r"C:\Projects\YosemiteNP\Yosemite.aprx") m = aprx.listMaps('CAD')[0] # Select the CAD sub layer to update lyr = m.listLayers('Parcels')[0] # Access layer CIM lyrCIM = lyr.getDefinition("V2") dc = lyrCIM.featureTable.dataConnection # Update the feature dataset with the new CAD file name dc.featureDataset = "NewParcels.dwg" # Update layer CIM lyr.setDefinition(lyrCIM) aprx.saveACopy(r"C:\Projects\YosemiteNP\YosemiteNew.aprx")
Этот скрипт изменяет источник данных связи в слое. Скрипт изменяет состоящие в связи набор данных, набор классов объектов и файловую базу геоданных.
import arcpy # Specify the new relate properties newGDB = "FGDB2.gdb" newFeatureClass = "Cities2" newFeatureDataSet = "USA2" newRelateName = "New Relate" # Reference project, map and layer p = arcpy.mp.ArcGISProject('current') m = p.listMaps('Relate Map')[0] l = m.listLayers('States')[0] # Get the layer's CIM definition lyrCIM = l.getDefinition('V2') # Get the first relate on the layer relate = lyrCIM.featureTable.relates[0] # Get the data connection properties for the relate dc = relate.dataConnection # Change the connection string to point to the new File Geodatabase dc.workspaceConnectionString = dc.workspaceConnectionString.replace("FGDB.gdb", newGDB) # Change the dataset name dc.dataset = newFeatureClass # If the data is in a Feature Dataset, then update it if hasattr(dc, "featureDataset"): dc.featureDataset = newFeatureDataSet # Change the relate's name relate.name = newRelateName # Set the layer's CIM definition l.setDefinition(lyrCIM)