¿Copiando la geodatabase de ArcSDE a la geodatabase de archivos usando ArcPy?

9

Me gustaría hacer una copia exacta (dominios, conjuntos de datos de entidades, clases de entidades, etc.) de una base de datos SDE a una geodatabase de archivos.

He probado varias posibilidades, que incluyen:

  1. utilizando el proceso de copia (gestión de datos)
  2. creando un nuevo GDB y copiando manualmente cada conjunto de datos de características desde el SDE
  3. exportar un documento de espacio de trabajo xml desde el SDE e importarlo al GDB

El Copy_managementproceso no parece funcionar para copiar un SDE a un GDB, ya que los tipos de datos de entrada y salida deben coincidir.

El proceso de importación de cada conjunto de datos de características en un nuevo GDB probablemente también podría automatizarse utilizando Copy_management iterando a través de cada conjunto de datos de características, aunque parece que esto podría causar problemas de una copia incompleta si hubiera un error con uno de los procesos.

Exportar e importar espacios de trabajo xml parece funcionar, aunque este proceso crea archivos increíblemente grandes cuando el proceso se utiliza en geodatabases grandes.

¿Existe una forma más directa de copiar el contenido y el esquema de un SDE a un GDB que las formas mencionadas, de manera que pueda automatizarse?

Si no, ¿hay alguna razón por la cual las posibilidades anteriores no deberían usarse en este proceso?

Krausers
fuente
1
Relacionado: gis.stackexchange.com/q/63368/753
blah238

Respuestas:

5

La única forma de obtener una copia real de los datos (dominios, conjuntos de datos, relaciones, etc.) es usar el método manual de copiar y pegar dentro del catálogo. ESRI aún no nos ha dado la capacidad de transferir estos datos de ninguna otra manera con una sola operación que se puede programar fácilmente.

Tengo un proceso nocturno que copia mis dos bases de datos SDE principales en geodatabases de archivos para la continuidad de las operaciones. Esto es para que, en caso de emergencia, mi personal tenga algunos datos para trabajar hasta que mi tienda de TI pueda reconstruir mi SDE a partir de la copia de seguridad. Después de muchas pruebas y errores, he decidido que podemos vivir con las limitaciones de usar FeatureClassToFeatureClass_conversion y TableToTable_conversion para transferir nuestros datos todas las noches.

Sí, perdemos parte de la funcionalidad de la geodatabase, pero ahora se ejecutará desatendida por la noche y está lista para funcionar tan pronto como la obtenga. En mi caso, la única funcionalidad que realmente nos falta (suponiendo que opere en un modo de emergencia) es que mis clases de relación se rompen porque la conversión restablece los ObjectID que vinculan las dos tablas.

Hasta que ESRI nos brinde más opciones, tendrá que ver qué está dispuesto a sacrificar en este momento; tiempo y esfuerzo o funcionalidad?

Lémur
fuente
¿Un documento xml worskspace no funcionaría?
Jyler
8

Sé que esta publicación es un poco vieja, pero pensé que compartiría mi respuesta ya que me enfrenté al mismo problema. El siguiente script DEBE copiar todas las tablas, clases de entidad y relaciones que no estén en un conjunto de datos y también copiará sobre todos los conjuntos de datos, incluidas las clases de entidad, la topología, etc. dentro del conjunto de datos. Se saltará cualquier error durante la copia y continuará. Producirá un archivo de registro que contiene datos como el recuento de elementos de la base de datos de origen y el recuento de elementos de destino para que pueda comparar la copia y también registrará los errores que encuentre.

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)   

Tuve mucha suerte con esto. Estaba replicando una base de datos SDE en una geodatabase de archivos. Sin embargo, no he realizado pruebas exhaustivas con este script, ya que satisfizo todas mis necesidades. Lo probé usando ArcGIS 10.3. Además, una cosa a tener en cuenta, estaba en conversaciones con alguien que ha usado este script y se encontraron con un problema con un error al copiar ciertos conjuntos de datos debido a permisos incorrectos y tablas vacías.

Lemur: ¿por qué no crear sus relaciones basadas en una identificación global en lugar de la identificación del objeto? Que tus relaciones se preservarían. Si no ha creado identificaciones globales, lo recomendaría encarecidamente.

-actualizar

Agregué un poco más de lógica al código para manejar rutas de conexión de base de datos incorrectas y un mejor registro y manejo de errores:

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
fuente
Peter, utilicé el script que proporcionaste y actualicé las 2 variables en la parte inferior. Recibo un error Traceback (última llamada): archivo "ServerPath \\ CopySDEtoGDB.py", línea 90, en <module> replicateDatabase (databaseConnection, targetGDB) Archivo "ServerPath \\ CopySDEtoGDB.py", línea 55, en replicateDatabase datasetList = [arcpy.Describe (a) .name para a en arcpy.ListDatasets ()] TypeError: el objeto 'NoneType' no es iterable ¿Alguna pista de lo que esto significa?
Courtney
Courtney: parece que hay un error tipográfico o un ligero error en la ruta a la variable de conexión de la base de datos. Está arrojando un error porque está intentando iterar sobre una lista que está vacía en la línea 55. Pude volver a crear el error que obtuvo al usar la ruta incorrecta en la variable "databaseConnection". ¿Cuál es la ruta real que usó en la variable?
PMK
Si quisiera hacer esto todas las noches, ¿no sobrescribirá las funciones existentes? No quiero crear un nuevo FGD cada vez que solo quiero sobrescribir el objetivo existente.
NULL.Dude
Peter si el GDB objetivo existe, el script falla
NULL.Dude
2

He usado un guión similar al de Peter arriba y tuve buena suerte, aunque la suya es mejor. Una cosa para señalar que puede hacer tropezar a alguien es que si está utilizando geoprocesamiento de python de 64 bits y tiene ArcFM cargado sobre ESRI, fallará en todas las características que se han configurado para usar ArcFM o Designer con un ERROR 000260. Esto es porque tienes que usar python de 32 bits o las cosas de ArcFM no se licenciarán correctamente.

Para obtener una descripción más detallada del uso de ArcPy de 32 bits, consulte los primeros dos comentarios sobre este hilo en Exchange

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

Rrankman
fuente
Si esos dos comentarios proporcionan la respuesta a esta pregunta, entonces su contenido debe citarse o resumirse aquí y no solo vincularse a él; consulte meta.stackexchange.com/questions/225370/…. Si ya ha proporcionado un resumen, tal vez solo cambie "Verificar los primeros dos comentarios en este hilo en Exchange "a" Para una descripción más detallada, vea los dos primeros comentarios en este hilo en Exchange ".
PolyGeo
0

Si tiene privilegios de administrador, puede usar comandos simples de copiar y pegar para exportar o importar archivos SDE a la geo-base de datos y viceversa. Consulte aquí para obtener más detalles.

Ganeshnarim
fuente
Gracias Ganeshnarim: me gustaría automatizar el proceso utilizando Python, por lo que cualquier proceso manual de copiar / pegar en ArcCatalog no satisfaría mis necesidades. También he tenido un éxito limitado con este método, ya que parece (en ArcMap 10.1) copiar un SDE simplemente crea otro enlace a la misma base de datos (mientras que si esta misma técnica se usara en un archivo o geodatabase personal, se haría una copia)
Krausers