Скопіювати базу геоданих ArcSDE у файл бази даних geodata за допомогою ArcPy?


9

Я хотів би зробити точну копію (домени, набори даних функцій, класи функцій тощо) бази даних SDE у базу даних геоданих.

Я спробував кілька можливостей, серед яких:

  1. за допомогою процесу копіювання (управління даними)
  2. створивши новий GDB та вручну скопіювавши кожен набір даних із SDE
  3. експорт документа робочої області xml з SDE та імпортування його в GDB

Copy_managementПроцес не здається , що це буде працювати для копіювання SDE до БГД, так як типи даних , вхідні і вихідні повинні збігатися.

Процес імпорту кожного набору даних функції в новий GDB, ймовірно, може бути автоматизований за допомогою Copy_management, а також ітерацією через кожен набір даних, хоча, мабуть, це може спричинити проблеми неповної копії, якщо виникла помилка в одному з процесів.

Експорт та імпорт робочих просторів XML, здається, працює, хоча цей процес створює неймовірно великі файли, коли процес використовується на великих базах даних про геодані.

Чи існує більш простий спосіб скопіювати вміст та схему SDE в GDB, ніж вказані способи, таким чином, який можна автоматизувати?

Якщо ні, то чи є причини, що вищезазначені можливості не слід використовувати в цьому процесі?


Відповіді:


5

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

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

Так, ми втрачаємо частину функціональної бази геоданих, але вона буде працювати без нагляду вночі і готова працювати, як тільки я її отримаю. У моєму випадку єдиною функціональністю, якої нам справді не вистачає (припускаючи, що вона працює в аварійному режимі), є те, що класи моїх відносин порушені, оскільки перетворення скидає ObjectID, які пов'язують дві таблиці.

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


Документ для файлів xml для роботи не працюватиме?
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('--------------------------------------------------')

Петро, ​​я використав сценарій, який ти надав, і я оновив дві змінні внизу. Я отримую помилку Traceback (останній дзвінок останній): Файл "ServerPath \\ CopySDEtoGDB.py", рядок 90, у <module> replicateDatabase (databaseConnection, targetGDB) Файл "ServerPath \\ CopySDEtoGDB.py", рядок 55, у replicateDatabase databaseList = [arcpy.Describe (a). ім'я для a в arcpy.ListDatasets ()] TypeError: 'NoneType' об'єкт не доступний. Будь-яке поняття, що це означає?
Кортні

Кортні - Це здається, що на шляху до змінної підключення до вашої бази даних є помилка друку або незначна помилка. Це помилка, оскільки вона намагається повторити список, порожній у рядку 55. Я зміг відтворити помилку, яку ви отримали, використовуючи неправильний шлях у змінній "databaseConnection". який фактичний шлях ви використовували в змінній?
ПМК

Якщо я хотів це робити щоночі, він не буде перезаписувати наявні функції? Я не хочу створювати новий FGD кожен раз, коли я просто хочу замінити існуючу ціль.
NULL.Dude

Пітер, якщо цільовий GDB існує, сценарій не вдасться
NULL.Dude

2

Я використав сценарій, подібний до Петра вище, і мені пощастило, хоча його краще. Одне, що слід зазначити, що хтось може вимкнути це, якщо ви використовуєте 64-бітну пітонічну обробку і у вас ArcFM завантажений поверх ESRI, це не вдасться до всіх функцій, встановлених для використання ArcFM або Designer з ПОМИЛОЮ 000260. Це це тому, що вам доведеться використовувати 32-бітний пітон, або речі ArcFM не ліцензуються належним чином.

Більш детальний опис використання 32-бітного ArcPy див. У перших двох коментарях до цього потоку в Exchange

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


Якщо ці два зауваження дають відповідь на це питання , то їх зміст має бути або цитироваться або коротко тут , а не тільки пов'язані з - см meta.stackexchange.com/questions/225370 / ... Якщо ви вже представили резюме , можливо , просто змінити «Check опублікуйте перші два коментарі до цього потоку в Exchange "до" Для більш детального опису див. перші два коментарі до цього потоку в Exchange ".
PolyGeo

0

Якщо у вас є права адміністратора, ви можете скористатися простими командами копіювання та вставки, щоб експортувати або імпортувати sde, щоб навпаки подати геобазу даних, і ознайомтесь тут, щоб отримати докладнішу інформацію.


Дякую Ганешнариму - я хотів би автоматизувати процес за допомогою Python, тому будь-який процес копіювання / вставки вручну в ArcCatalog не відповідав би моїм потребам. Я також мав обмежений успіх у цьому методі, оскільки, здається, (в ArcMap 10.1) копіювання SDE просто створює ще одне посилання на ту саму базу даних (тоді як, якби ця сама техніка використовувалася у файлі чи на персональній базі даних, копія буде зроблена)
Krausers
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.