Копировать базу геоданных ArcSDE в файловую базу геоданных с помощью ArcPy?

9

Я хотел бы сделать точную копию (домены, наборы классов объектов, классы объектов и т. Д.) Базы данных SDE в файловую базу геоданных.

Я испробовал несколько возможностей, в том числе:

  1. используя процесс копирования (управления данными)
  2. создание новой GDB и ручное копирование каждого набора классов объектов из SDE
  3. экспорт документа рабочей области xml из SDE и импорт его в GDB

Copy_managementПроцесс не кажется , что это будет работать для копирования SDE к БГД, так как типы данных , входные и выходные должны совпадать.

Процесс импорта каждого набора классов объектов в новую GDB, вероятно, можно автоматизировать с помощью Copy_management, перебирая каждый набор классов объектов, хотя, по-видимому, это может вызвать проблемы с неполной копией, если в одном из процессов произошла ошибка.

Экспорт и импорт рабочих пространств xml, похоже, работает, хотя этот процесс создает невероятно большие файлы, когда процесс используется в больших базах геоданных.

Есть ли более простой способ скопировать содержимое и схему SDE в GDB, чем упомянутые способы, способом, который можно автоматизировать?

Если нет, есть ли причины, по которым вышеуказанные возможности не следует использовать в этом процессе?

Krausers
источник
1
Связанный: gis.stackexchange.com/q/63368/753
blah238

Ответы:

5

Единственный способ получить точную копию данных (домены, наборы данных, отношения и т. Д.) - это использовать метод ручного копирования и вставки внутри каталога. ESRI еще не дал нам возможность передавать эти данные любым другим способом с помощью одной операции, которая может быть легко написана.

У меня есть ночной процесс, который копирует мои две основные базы данных SDE в файловые базы геоданных для обеспечения непрерывности операций. Это сделано для того, чтобы в случае чрезвычайной ситуации мои сотрудники могли работать с некоторыми данными, пока мой ИТ-магазин не сможет восстановить мой SDE из резервной копии. После долгих проб и ошибок я решил, что мы можем жить с ограничениями использования FeatureClassToFeatureClass_conversion и TableToTable_conversion для передачи наших данных каждую ночь.

Да, мы утратили некоторые функции базы геоданных, но теперь она будет работать без присмотра ночью и будет готова к работе, как только я ее получу. В моем случае единственная функциональность, которую нам действительно не хватает (при условии работы в аварийном режиме), состоит в том, что мои классы отношений нарушены, потому что преобразование сбрасывает ObjectID, которые связывают две таблицы.

Пока ESRI не предоставит нам больше возможностей, вам придется посмотреть, чем вы готовы пожертвовать в данный момент; время и усилия или функциональность?

Лемур
источник
Документ XML Worskspace не будет работать?
Jyler
8

Я знаю, что этот пост немного староват, но я хотел бы поделиться своим ответом, поскольку столкнулся с той же проблемой. Следующий скрипт ДОЛЖЕН скопировать все таблицы, классы пространственных объектов и связи, не входящие в набор данных, а также скопировать все наборы данных, включая классы пространственных объектов, топологию и т. Д. В наборе данных. Он пропустит любые ошибки во время копирования и продолжения работы. Он создаст файл журнала, который содержит такие данные, как количество элементов в исходной БД и количество пунктов назначения, чтобы вы могли сравнить копию, и он также будет регистрировать ошибки, с которыми он сталкивается.

import arcpy, os, shutil, time
import logging as log
from datetime import datetime

def formatTime(x):
    minutes, seconds_rem = divmod(x, 60)
    if minutes >= 60:
        hours, minutes_rem = divmod(minutes, 60)
        return "%02d:%02d:%02d" % (hours, minutes_rem, seconds_rem)
    else:
        minutes, seconds_rem = divmod(x, 60)
        return "00:%02d:%02d" % (minutes, seconds_rem)

def getDatabaseItemCount(workspace):
    arcpy.env.workspace = workspace
    feature_classes = []
    for dirpath, dirnames, filenames in arcpy.da.Walk(workspace,datatype="Any",type="Any"):
        for filename in filenames:
            feature_classes.append(os.path.join(dirpath, filename))
    return feature_classes, len(feature_classes)

def replicateDatabase(dbConnection, targetGDB):
    startTime = time.time()

    featSDE,cntSDE = getDatabaseItemCount(dbConnection)
    featGDB,cntGDB = getDatabaseItemCount(targetGDB)

    now = datetime.now()
    logName = now.strftime("SDE_REPLICATE_SCRIPT_%Y-%m-%d_%H-%M-%S.log")
    log.basicConfig(datefmt='%m/%d/%Y %I:%M:%S %p', format='%(asctime)s %(message)s',\
    filename=logName,level=log.INFO)

    print "Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB)
    log.info("Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB))
    print "Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE)
    log.info("Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE))

    arcpy.env.workspace = dbConnection

    #deletes old targetGDB
    try:
        shutil.rmtree(targetGDB)
        print "Deleted Old %s" %(os.path.split(targetGDB)[-1])
        log.info("Deleted Old %s" %(os.path.split(targetGDB)[-1]))
    except Exception as e:
        print e
        log.info(e)

    #creates a new targetGDB
    GDB_Path, GDB_Name = os.path.split(targetGDB)
    print "Now Creating New %s" %(GDB_Name)
    log.info("Now Creating New %s" %(GDB_Name))
    arcpy.CreateFileGDB_management(GDB_Path, GDB_Name)

    datasetList = [arcpy.Describe(a).name for a in arcpy.ListDatasets()]
    featureClasses = [arcpy.Describe(a).name for a in arcpy.ListFeatureClasses()]
    tables = [arcpy.Describe(a).name for a in arcpy.ListTables()]

    #Compiles a list of the previous three lists to iterate over
    allDbData = datasetList + featureClasses + tables

    for sourcePath in allDbData:
        targetName = sourcePath.split('.')[-1]
        targetPath = os.path.join(targetGDB, targetName)
        if arcpy.Exists(targetPath)==False:
            try:
                print "Atempting to Copy %s to %s" %(targetName, targetPath)
                log.info("Atempting to Copy %s to %s" %(targetName, targetPath))
                arcpy.Copy_management(sourcePath, targetPath)
                print "Finished copying %s to %s" %(targetName, targetPath)
                log.info("Finished copying %s to %s" %(targetName, targetPath))
            except Exception as e:
                print "Unable to copy %s to %s" %(targetName, targetPath)
                print e
                log.info("Unable to copy %s to %s" %(targetName, targetPath))
                log.info(e)
        else:
            print "%s already exists....skipping....." %(targetName)
            log.info("%s already exists....skipping....." %(targetName))
    featGDB,cntGDB = getDatabaseItemCount(targetGDB)
    print "Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB)
    log.info("Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB))
    totalTime = (time.time() - startTime)
    totalTime = formatTime(totalTime)
    log.info("Script Run Time: %s" %(totalTime))

if __name__== "__main__":
    databaseConnection = r"YOUR_SDE_CONNECTION"
    targetGDB = "DESTINATION_PATH\\SDE_Replicated.gdb"
    replicateDatabase(databaseConnection, targetGDB)   

Мне очень повезло с этим. Я реплицировал базу данных SDE в файловую базу геоданных. Я не слишком много тестировал этот скрипт, так как он удовлетворял все мои потребности. Я протестировал его с помощью ArcGIS 10.3. Кроме того, следует отметить, что я разговаривал с кем-то, кто использовал этот сценарий, и у них возникла проблема с ошибкой при копировании определенных наборов данных из-за неправильных разрешений и пустых таблиц.

Лемур - почему бы не создать свои отношения на основе глобального идентификатора вместо идентификатора объекта? Это вы ваши отношения будут сохранены. Если вы не создали глобальные идентификаторы, я очень рекомендую это.

-Обновить

Я добавил немного больше логики в код для обработки неправильных путей соединения с базой данных и лучшей регистрации и обработки ошибок:

import time, os, datetime, sys, logging, logging.handlers, shutil
import arcpy

########################## user defined functions ##############################

def getDatabaseItemCount(workspace):
    log = logging.getLogger("script_log")
    """returns the item count in provided database"""
    arcpy.env.workspace = workspace
    feature_classes = []
    log.info("Compiling a list of items in {0} and getting count.".format(workspace))
    for dirpath, dirnames, filenames in arcpy.da.Walk(workspace,datatype="Any",type="Any"):
        for filename in filenames:
            feature_classes.append(os.path.join(dirpath, filename))
    log.info("There are a total of {0} items in the database".format(len(feature_classes)))
    return feature_classes, len(feature_classes)

def replicateDatabase(dbConnection, targetGDB):
    log = logging.getLogger("script_log")
    startTime = time.time()

    if arcpy.Exists(dbConnection):
        featSDE,cntSDE = getDatabaseItemCount(dbConnection)
        log.info("Geodatabase being copied: %s -- Feature Count: %s" %(dbConnection, cntSDE))
        if arcpy.Exists(targetGDB):
            featGDB,cntGDB = getDatabaseItemCount(targetGDB)
            log.info("Old Target Geodatabase: %s -- Feature Count: %s" %(targetGDB, cntGDB))
            try:
                shutil.rmtree(targetGDB)
                log.info("Deleted Old %s" %(os.path.split(targetGDB)[-1]))
            except Exception as e:
                log.info(e)

        GDB_Path, GDB_Name = os.path.split(targetGDB)
        log.info("Now Creating New %s" %(GDB_Name))
        arcpy.CreateFileGDB_management(GDB_Path, GDB_Name)

        arcpy.env.workspace = dbConnection

        try:
            datasetList = [arcpy.Describe(a).name for a in arcpy.ListDatasets()]
        except Exception, e:
            datasetList = []
            log.info(e)
        try:
            featureClasses = [arcpy.Describe(a).name for a in arcpy.ListFeatureClasses()]
        except Exception, e:
            featureClasses = []
            log.info(e)
        try:
            tables = [arcpy.Describe(a).name for a in arcpy.ListTables()]
        except Exception, e:
            tables = []
            log.info(e)

        #Compiles a list of the previous three lists to iterate over
        allDbData = datasetList + featureClasses + tables

        for sourcePath in allDbData:
            targetName = sourcePath.split('.')[-1]
            targetPath = os.path.join(targetGDB, targetName)
            if not arcpy.Exists(targetPath):
                try:
                    log.info("Atempting to Copy %s to %s" %(targetName, targetPath))
                    arcpy.Copy_management(sourcePath, targetPath)
                    log.info("Finished copying %s to %s" %(targetName, targetPath))
                except Exception as e:
                    log.info("Unable to copy %s to %s" %(targetName, targetPath))
                    log.info(e)
            else:
                log.info("%s already exists....skipping....." %(targetName))

        featGDB,cntGDB = getDatabaseItemCount(targetGDB)
        log.info("Completed replication of %s -- Feature Count: %s" %(dbConnection, cntGDB))

    else:
        log.info("{0} does not exist or is not supported! \
        Please check the database path and try again.".format(dbConnection))

#####################################################################################

def formatTime(x):
    minutes, seconds_rem = divmod(x, 60)
    if minutes >= 60:
        hours, minutes_rem = divmod(minutes, 60)
        return "%02d:%02d:%02d" % (hours, minutes_rem, seconds_rem)
    else:
        minutes, seconds_rem = divmod(x, 60)
        return "00:%02d:%02d" % (minutes, seconds_rem)

if __name__ == "__main__":
    startTime = time.time()
    now = datetime.datetime.now()

    ############################### user variables #################################
    '''change these variables to the location of the database being copied, the target 
    database location and where you want the log to be stored'''

    logPath = ""
    databaseConnection = "path_to_sde_or_gdb_database"
    targetGDB = "apth_to_replicated_gdb\\Replicated.gdb"

    ############################### logging items ###################################
    # Make a global logging object.
    logName = os.path.join(logPath,(now.strftime("%Y-%m-%d_%H-%M.log")))

    log = logging.getLogger("script_log")
    log.setLevel(logging.INFO)

    h1 = logging.FileHandler(logName)
    h2 = logging.StreamHandler()

    f = logging.Formatter("[%(levelname)s] [%(asctime)s] [%(lineno)d] - %(message)s",'%m/%d/%Y %I:%M:%S %p')

    h1.setFormatter(f)
    h2.setFormatter(f)

    h1.setLevel(logging.INFO)
    h2.setLevel(logging.INFO)

    log.addHandler(h1)
    log.addHandler(h2)

    log.info('Script: {0}'.format(os.path.basename(sys.argv[0])))

    try:
        ########################## function calls ######################################

        replicateDatabase(databaseConnection, targetGDB)

        ################################################################################
    except Exception, e:
        log.exception(e)

    totalTime = formatTime((time.time() - startTime))
    log.info('--------------------------------------------------')
    log.info("Script Completed After: {0}".format(totalTime))
    log.info('--------------------------------------------------')
ПМК
источник
Питер, я использовал предоставленный тобой скрипт и обновил 2 переменные внизу. Я получаю сообщение об ошибке трассировки (последний вызов был последним): файл «ServerPath \\ CopySDEtoGDB.py», строка 90, в <module> replicateDatabase (databaseConnection, targetGDB), файл «ServerPath \\ CopySDEtoGDB.py», строка 55, в replicateDatabase datasetList = [arcpy.Describe (a) .name для объекта в arcpy.ListDatasets ()] TypeError: объект 'NoneType' не повторяется. Любая подсказка, что это значит?
Кортни
Кортни - Похоже, что в пути к вашей переменной подключения к базе данных есть опечатка или небольшая ошибка. Он выдает ошибку, потому что пытается перебрать список, пустой в строке 55. Мне удалось воссоздать ошибку, которую вы получили, используя неверный путь в переменной «databaseConnection». какой фактический путь вы использовали в переменной?
PMK
Если бы я хотел сделать это по ночам, это не перезаписывает существующие функции? Я не хочу создавать новый FGD каждый раз, когда просто хочу перезаписать существующую цель.
NULL. Чувак
Питер, если целевой GDB существует, сценарий не выполняется
NULL. Dude
2

Я использовал сценарий, похожий на сценарий Питера, и мне повезло, хотя он лучше. Следует отметить, что если кто-то использует геообработку на 64-битном питоне и у вас загружен ArcFM поверх ESRI, он не будет работать на всех объектах, для которых было установлено использование ArcFM или Designer с ОШИБКОЙ 000260. потому что вы должны использовать 32-битный Python, иначе ArcFM не будет правильно лицензироваться.

Более подробное описание использования 32-битной ArcPy см. В первых двух комментариях к этой теме в Exchange.

https://infrastructurecommunity.schneider-electric.com/docs/DOC-2563

rrankman
источник
Если эти два комментария дают ответ на этот вопрос, то их содержание должно быть либо цитировано, либо обобщено здесь, а не просто связано с ним - см. Meta.stackexchange.com/questions/225370/… Если вы уже предоставили резюме, возможно, просто измените «Проверить Из первых двух комментариев по этой теме в Exchange "к" Более подробное описание смотрите по первым двум комментариям по этой теме в Exchange ".
PolyGeo
0

Если у вас есть права администратора, вы можете использовать простые команды копирования и вставки, чтобы экспортировать или импортировать sde в файл гео-базы данных, и посмотрите здесь для получения дополнительной информации.

Ganeshnarim
источник
Спасибо Ganeshnarim - я хотел бы автоматизировать процесс с использованием Python, поэтому любой ручной процесс копирования / вставки в ArcCatalog не будет соответствовать моим потребностям. У меня также был ограниченный успех с этим методом, так как кажется (в ArcMap 10.1) копирование SDE просто создает другую ссылку на ту же базу данных (тогда как если бы этот же метод использовался в файловой или личной базе геоданных, была бы сделана копия)
Krausers