Copie de la géodatabase ArcSDE dans une géodatabase fichier à l'aide d'ArcPy?

9

Je voudrais faire une copie exacte (domaines, jeux de données d'entités, classes d'entités, etc.) d'une base de données SDE dans une géodatabase fichier.

J'ai essayé plusieurs possibilités, notamment:

  1. à l'aide du processus de copie (gestion des données)
  2. créer un nouveau GDB et copier manuellement chaque jeu de données d'entité à partir du SDE
  3. exportation d'un document d'espace de travail xml à partir du SDE et importation dans le GDB

Le Copy_managementprocessus ne semble pas fonctionner pour copier un SDE dans un GDB, car les types de données d'entrée et de sortie doivent correspondre.

Le processus d'importation de chaque jeu de données d'entité dans un nouveau GDB pourrait probablement être automatisé à l'aide de Copy_management également en itérant à travers chaque jeu de données d'entité, bien qu'il semble que cela puisse causer des problèmes de copie incomplète s'il y avait une erreur avec l'un des processus.

L'exportation et l'importation d'espaces de travail xml semblent fonctionner, bien que ce processus crée des fichiers incroyablement volumineux lorsqu'il est utilisé sur de grandes géodatabases.

Existe-t-il un moyen plus simple de copier le contenu et le schéma d'un SDE vers un GDB que les méthodes mentionnées, d'une manière qui peut être automatisée?

Sinon, y a-t-il des raisons pour lesquelles les possibilités ci-dessus ne devraient pas être utilisées dans ce processus?

Krausers
la source

Réponses:

5

La seule façon d'obtenir une copie fidèle des données (domaines, jeux de données, relations, etc.) consiste à utiliser la méthode manuelle de copier-coller dans le catalogue. ESRI ne nous a pas encore donné la possibilité de transférer ces données par tout autre moyen avec une seule opération qui peut être facilement scriptée.

J'ai un processus nocturne qui copie mes deux bases de données SDE principales pour archiver des géodatabases pour la continuité des opérations. Il en est ainsi qu'en cas d'urgence, mon personnel a des données à travailler jusqu'à ce que mon magasin informatique puisse reconstruire mon SDE à partir d'une sauvegarde. Après de nombreux essais et erreurs, j'ai décidé que nous pouvions vivre avec les limites de l'utilisation de FeatureClassToFeatureClass_conversion et TableToTable_conversion pour transférer nos données chaque nuit.

Oui, nous perdons certaines des fonctionnalités de la géodatabase, mais elle fonctionnera désormais sans surveillance la nuit et est prête à fonctionner dès que je l'obtiens. Dans mon cas, la seule fonctionnalité qui nous manque vraiment (en supposant un fonctionnement en mode d'urgence) est que mes classes de relations sont rompues car la conversion réinitialise les ObjectID qui relient les deux tables.

Jusqu'à ce que ESRI nous donne plus d'options, vous devrez examiner ce que vous êtes prêt à sacrifier pour le moment; temps et effort ou fonctionnalité?

Maki
la source
Un document xml worskspace ne fonctionnerait pas?
Jyler
8

Je sais que ce message est un peu vieux mais je pensais que je partagerais ma réponse car j'étais confronté au même problème. Le script suivant DEVRAIT copier toutes les tables, classes d'entités et relations ne se trouvant pas dans un jeu de données et copiera également tous les jeux de données, y compris les classes d'entités, la topologie, etc. dans le jeu de données. Il sautera toutes les erreurs pendant la copie et continuera. Il produira un fichier journal qui contient des données telles que le nombre d'éléments de base de données source et le nombre d'éléments de destination afin que vous puissiez comparer la copie et enregistrera également les erreurs qu'il rencontre.

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)   

J'ai vraiment eu de la chance avec ça. Je répliquais une base de données SDE dans une géodatabase fichier. Je n'ai pas fait trop de tests sur ce script car il répondait à tous mes besoins. Je l'ai testé à l'aide d'ArcGIS 10.3. En outre, une chose à noter, j'étais en pourparlers avec quelqu'un qui a utilisé ce script et ils ont rencontré un problème avec une erreur de copie de certains ensembles de données en raison d'autorisations incorrectes et de tables vides.

Lémurien - pourquoi ne pas créer vos relations basées sur un identifiant global au lieu de l'identifiant d'objet? Que vous vos relations soient préservées. Si vous n'avez pas créé d'identifiants globaux, je le recommande vivement.

-mise à jour

J'ai ajouté un peu plus de logique dans le code pour gérer les mauvais chemins de connexion à la base de données et une meilleure journalisation et meilleure gestion des erreurs:

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
la source
Peter, j'ai utilisé le script que vous avez fourni et j'ai mis à jour les 2 variables en bas. Je reçois une erreur Traceback (dernier appel le plus récent): fichier "ServerPath \\ CopySDEtoGDB.py", ligne 90, dans <module> replicateDatabase (databaseConnection, targetGDB) Fichier "ServerPath \\ CopySDEtoGDB.py", ligne 55, dans replicateDatabase datasetList = [arcpy.Describe (a) .name pour un dans arcpy.ListDatasets ()] TypeError: L'objet 'NoneType' n'est pas itérable. Un indice ce que cela signifie?
Courtney
Courtney - Il semble qu'il y ait une faute de frappe ou une légère erreur dans le chemin d'accès à votre variable de connexion à la base de données. Il génère une erreur car il essaie d'itérer sur une liste vide sur la ligne 55. J'ai pu recréer l'erreur que vous avez obtenue en utilisant le chemin incorrect dans la variable "databaseConnection". quel est le chemin réel que vous avez utilisé dans la variable?
PMK
Si je voulais le faire tous les soirs, cela n'écraserait pas les fonctionnalités existantes? Je ne veux pas créer un nouveau FGD chaque fois que je veux juste écraser la cible existante.
NULL.Dude
Peter si le GDB cible existe, le script échoue
NULL.Dude
2

J'ai utilisé un script similaire à celui de Peter ci-dessus et j'ai eu de la chance, bien que le sien soit meilleur. Une chose à souligner qui pourrait déclencher quelqu'un est que si vous utilisez le géotraitement Python 64 bits et que vous avez ArcFM chargé par-dessus ESRI, il échouera sur toutes les fonctionnalités qui ont été définies pour utiliser ArcFM ou Designer avec une ERREUR 000260. Cette est parce que vous devez utiliser du python 32 bits ou les trucs ArcFM ne seront pas correctement sous licence.

Pour une description plus détaillée de l'utilisation d'ArcPy 32 bits, consultez les deux premiers commentaires sur ce fil dans Exchange

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

rrankman
la source
Si ces deux commentaires fournissent la réponse à cette question, leur contenu doit être soit cité, soit résumé ici et non seulement lié à - voir meta.stackexchange.com/questions/225370/… Si vous avez déjà fourni un résumé, peut-être simplement changer "Vérifier sur les deux premiers commentaires sur ce fil dans Exchange "à" Pour une description plus détaillée, consultez les deux premiers commentaires sur ce fil dans Exchange ".
PolyGeo
0

Si vous avez des privilèges d'administrateur, vous pouvez utiliser des commandes simples de copier-coller pour exporter ou importer sde dans un fichier géo-base de données et vice versa et consultez ici pour plus de détails.

Ganeshnarim
la source
Merci Ganeshnarim - Je voudrais automatiser le processus en utilisant Python, donc tout processus de copier / coller manuel dans ArcCatalog ne répondrait pas à mes besoins. J'ai également eu un succès limité avec cette méthode, car il semble (dans ArcMap 10.1) que la copie d'un SDE crée simplement un autre lien vers la même base de données (alors que si cette même technique était utilisée sur un fichier ou une géodatabase personnelle, une copie serait faite)
Krausers