Copiando o geodatabase do ArcSDE para arquivar o geodatabase usando o ArcPy?

9

Eu gostaria de fazer uma cópia exata (domínios, conjuntos de dados de recursos, classes de recursos etc.) de um banco de dados SDE para um banco de dados geográfico de arquivos.

Eu tentei várias possibilidades, incluindo:

  1. usando o processo de cópia (gerenciamento de dados)
  2. criando um novo GDB e copiando manualmente cada conjunto de dados de recursos do SDE
  3. exportando um documento da área de trabalho xml do SDE e importando-o para o GDB

O Copy_managementprocesso não parece funcionar para copiar uma SDE para um GDB, pois os tipos de dados de entrada e saída devem corresponder.

O processo de importação de cada conjunto de dados de recursos para um novo GDB provavelmente poderia ser automatizado usando o Copy_management, iterando cada conjunto de dados de recursos, embora pareça que isso poderia causar problemas em uma cópia incompleta se houvesse um erro em um dos processos.

Exportar e importar áreas de trabalho xml parece funcionar, embora esse processo crie arquivos incrivelmente grandes quando o processo é usado em grandes bancos de dados geográficos.

Existe uma maneira mais direta de copiar o conteúdo e o esquema de uma SDE para um GDB do que as maneiras mencionadas, de uma maneira que possa ser automatizada?

Caso contrário, existem razões pelas quais as possibilidades acima não devem ser usadas nesse processo?

Krausers
fonte
11
Veja também: gis.stackexchange.com/q/63368/753
blah238

Respostas:

5

A única maneira de obter uma cópia verdadeira dos dados (domínios, conjuntos de dados, relacionamentos etc.) é usar o método manual de copiar e colar no catálogo. A ESRI ainda não nos deu a capacidade de transferir esses dados de qualquer outra maneira com uma única operação que pode ser script facilmente.

Eu tenho um processo noturno que copia meus dois bancos de dados SDE principais para arquivar geodatabases para Continuidade de Operações. Isso ocorre para que, em caso de emergência, minha equipe tenha alguns dados para trabalhar até que minha loja de TI possa reconstruir meu SDE a partir do backup. Após muitas tentativas e erros, decidi que podemos conviver com as limitações do uso de FeatureClassToFeatureClass_conversion e TableToTable_conversion para transferir nossos dados todas as noites.

Sim, perdemos algumas das funcionalidades do banco de dados geográficos, mas agora ele é executado sem vigilância à noite e está pronto para ser utilizado assim que o receber. No meu caso, a única funcionalidade que realmente falta (assumindo a operação em modo de emergência) é que minhas classes de relacionamento estão quebradas porque a conversão redefine os ObjectIDs que vinculam as duas tabelas.

Até que a ESRI nos dê mais opções, você terá que analisar o que está disposto a sacrificar no momento; tempo e esforço ou funcionalidade?

Lêmure
fonte
Um documento XML Worskspace não funcionaria?
Jyler
8

Eu sei que este post é um pouco antigo, mas eu gostaria de compartilhar minha resposta desde que me deparei com o mesmo problema. O script a seguir DEVE copiar todas as tabelas, classes de recursos e relacionamentos que não estão em um conjunto de dados e também copiará todos os conjuntos de dados, incluindo as classes de recursos, topologia, etc. dentro do conjunto de dados. Irá ignorar quaisquer erros durante a cópia e continuar. Ele produzirá um arquivo de log que contém dados como a contagem de itens do banco de dados de origem e a contagem de itens de destino, para que você possa comparar a cópia e também registrará os erros encontrados.

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)   

Eu tive muita sorte com isso. Eu estava replicando um banco de dados SDE para um geodatabase de arquivo. Ainda não fiz muitos testes nesse script, pois ele atendeu a todas as minhas necessidades. Eu testei usando o ArcGIS 10.3. Além disso, uma coisa a observar, eu estava conversando com alguém que usou esse script e eles tiveram um problema ao copiar certos conjuntos de dados devido a permissões impróprias e tabelas vazias.

Lêmure - por que não criar seus relacionamentos com base em um ID global em vez do ID do objeto? Que seus relacionamentos seriam preservados. Se você não criou IDs globais, eu o recomendo.

-atualizar

Adicionei um pouco mais de lógica ao código para lidar com caminhos de conexão de banco de dados incorretos e melhor registro e tratamento de erros:

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('--------------------------------------------------')
PMK
fonte
Peter, usei o script que você forneceu e atualizei as 2 variáveis ​​na parte inferior. Estou recebendo um erro Traceback (última chamada mais recente): Arquivo "ServerPath \\ CopySDEtoGDB.py", linha 90, em <module> replicateDatabase (databaseConnection, targetGDB) Arquivo "ServerPath \\ CopySDEtoGDB.py", linha 55, em replicateDatabase datasetList = [arcpy.Describe (a) .name para a em arcpy.ListDatasets ()] TypeError: o objeto 'NoneType' não é iterável Alguma pista do que isso significa?
Courtney
Courtney - Parece que há um erro de digitação ou um pequeno erro no caminho para sua variável de conexão com o banco de dados. Está gerando um erro porque está tentando repetir uma lista que está vazia na linha 55. Consegui recriar o erro que você recebeu usando o caminho incorreto na variável "databaseConnection". qual é o caminho real que você usou na variável?
PMK
Se eu quisesse fazer isso todas as noites, ele não substituirá os recursos existentes? Eu não quero criar um novo FGD toda vez que eu quero substituir o destino existente.
NULL.Dude
Peter se o alvo GDB existe o script falhar
NULL.Dude
2

Eu usei um script semelhante ao de Peter acima e tive boa sorte, embora o dele seja melhor. Uma coisa a salientar que pode atrapalhar alguém é se você estiver usando geoprocessamento python de 64 bits e tiver o ArcFM carregado no ESRI, ele falhará em todos os recursos que foram configurados para usar o ArcFM ou Designer com um ERROR 000260. Isso é porque você precisa usar python de 32 bits ou o material do ArcFM não será licenciado corretamente.

Para obter uma descrição mais detalhada do uso do ArcPy de 32 bits, consulte os dois primeiros comentários sobre este segmento no Exchange

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

rrankman
fonte
Se esses dois comentários fornecerem a resposta a esta pergunta, seu conteúdo deverá ser citado ou resumido aqui e não apenas vinculado a - consulte meta.stackexchange.com/questions/225370/… Se você já forneceu um resumo, talvez mude " os dois primeiros comentários sobre este segmento no Exchange "para" Para obter uma descrição mais detalhada, consulte os dois primeiros comentários sobre este segmento no Exchange ".
PolyGeo
0

Se você possui privilégios de administrador, pode usar comandos simples de copiar e colar para exportar ou importar sde para arquivar geo-database vise versa e dê uma olhada aqui para obter mais detalhes.

Ganeshnarim
fonte
Obrigado Ganeshnarim - eu gostaria de automatizar o processo usando Python, portanto, qualquer processo manual de copiar / colar no ArcCatalog não atenderia às minhas necessidades. Eu também tive sucesso limitado com esse método, como parece (no ArcMap 10.1) copiar uma SDE simplesmente cria outro link para o mesmo banco de dados (enquanto que se essa mesma técnica fosse usada em um arquivo ou em um banco de dados pessoal, uma cópia seria feita)
Krausers