Лістинг класів функцій з активними доменами?


19

У мене є файл бази геоданих Esri з доменами атрибутів визначені. Мені потрібно видалити деякі домени атрибутів, але не можу, оскільки "Домен використовується правилом атрибута". . Як я можу виявити, які класи функцій використовують домени?

Executing: DeleteDomain R:\v5\YT_Canvec.gdb Permanency
Start Time: Thu May 19 11:01:02 2011
ERROR 999999: Error executing function.
The domain is used by an attribute rule.
Failed to execute (DeleteDomain).
Failed at Thu May 19 11:01:02 2011 (Elapsed Time: 0.00 seconds)

У базі геоданих є понад сто функціональних класів, інтерактивно дивлячись на властивості поля FC для кожного з них, є нестартер. Gdb занадто великий, щоб перетворити його на персональний gdb і перейти у задню двері з ms-доступом (у будь-якому разі хитрий метод).


(2011-травень-26): Ще один спосіб висловити це "який клас Feature використовує домен X?"


Чи використовуєте підтипові домени?
Кірк Куйкендалл

@kirk, так, є підтип, але домени, які я намагаюся видалити, не використовують підтип
matt wilkie

1
У такому випадку я думаю, що код Брайана спрацював би.
Кірк Куйкендалл

1
@kirk, виправлення: Я не думав, що я використовую підтипи + домени, але після довгого розмитнення та відкриття справи технічної підтримки, виявляється, я насправді використовував його. Це був справжній клік-фест, щоб визначити конкретний купріт, що залишився. Я повинен був би інвестувати більше часу на спостереження за вашим методом c #!
matt wilkie

Відповіді:


3

Відповісти на питання поводження з функціональними класами з підтипами, можна за допомогою arcpy (10.1+).

arcpy.env.workspace = your_gdb

for FC in arcpy.ListFeatureClasses():
    for stcode, stdict in list(arcpy.da.ListSubtypes(FC).items()):
        for stkey in list(stdict.keys()):
            if stkey == 'FieldValues':
                for field, fieldvals in list(stdict[stkey].items()):
                    if fieldvals[1] is not None:
                        print(
                            "{},{},{},{}".format(FC,
                                                 'None' if stcode == 0 else stdict['Name'],
                                                 field,
                                                 fieldvals[1].name))

Код підтипу, stcode, буде нульовим, якщо підтипів немає, тому код виводить напис "None".

Словник підтипу має більше до нього, так що перевірити його в коді.


Зміна моєї прийнятої відповіді на цю. Це коротко і прямо. Моя версія вашого коду на сайті github.com/envygeo/arcplus/blob/master/ArcToolbox/Scripts/… . Спасибі!
matt wilkie

21

У Python є методи перерахування класів функцій у базі даних геоданих, перегляд кожного класу функцій у списку, перелік полів кожного класу функцій та показ домену кожного поля.

import arcpy

#Set workspace environment to geodatabase
arcpy.env.workspace = your_gdb

#Get list of feature classes in geodatabase
FCs = arcpy.ListFeatureClasses()

#Loop through feature classes in list
for FC in FCs:

    #List fields in feature class
    fields = arcpy.ListFields(FC)

    #Loop through fields
    for field in fields:

        #Check if field has domain
        if field.domain != "":

            #Print feature class, field, domain name
            print FC, field.name, field.domain

Наведений вище код повинен працювати в ArcGIS 10, і він буде надрукувати список прямо у вікні інтерпретатора python. Потім можна скопіювати та вставити список у текстовий редактор або Excel, щоб легше переглянути результати.


Чи буде це також обробляти підтипові домени?
Кірк Куйкендалл

Я не впевнений, чи буде це обробляти підтипи або доменні підтипи. Я ніколи раніше не використовував підтипи. Якщо домену призначено певне поле, ім'я домену буде надруковано.
Брайан

прекрасно, дякую Брайану. Спочатку це не працювало для мене, але з часом я згадав, що listFC не повторюється в FeatureDatasets без додаткової допомоги ( gis.stackexchange.com/questions/5893/… ). Все добре зараз! :)
matt wilkie

@Kirk, ні він не бачить підтипів із використанням доменів.
matt wilkie

Дотримуйтесь прикладу resource.arcgis.com/en/help/main/10.1/index.html#//…, щоб пройти всі підтипи та пов’язані з ними домени.
Майкл Стімсон

8

Оскільки я не думаю, що python обробляє підтипи, я публікую цей c # код, який повинен. Я перевірив його на пробі води / стічних вод Esri і виявив такі невикористані домени:

HistoryType is not used
PLSSFirstDivisionType is not used
PLSSDirection is not used
PLSSPrincipalMeridian is not used
ParcelType is not used
PLSSSpecialSurveyType is not used
CartoLineType is not used
PLSSSecondDivisionType is not used

Часто DBA дратується, що домени - які по суті є таблицями пошуку - не можуть бути доступні через SQL.

Цей код перевірений з аркмапу ( оновлено за коментарем Метта):

protected override void OnClick()
{
    string fgdbPath = @"C:\projects\NetTools\InfrastructureEditingTemplate\MapsandGeodatabase\LocalGovernment.gdb";
    var dict = SummarizeDomains(fgdbPath);
    ListDomains(dict);
    // list what featureclasses use a particular domain ...
    string domName = "State_Bnd_Rules";
    if (dict.ContainsKey(domName))
    {
        if (dict[domName].Count > 0)
        {
            Debug.Print("{0} is used by these featureclasses: ", domName);
            foreach (string fcfldName in dict[domName])
            {
                Debug.Print("\t{0}", fcfldName);
            }
        }
        else
            Debug.Print("{0} is not used by any featureclasses", domName);
    }
    else
    {
        Debug.Print("Domain name not found in geodb: {0}", domName);
    }
}

private void ListDomains(Dictionary<string,List<string>> dict)
{
    foreach (KeyValuePair<string, List<string>> kvp in dict)
    {
        Debug.Print("Domain {0}",kvp.Key);
        if (kvp.Value.Count > 0)
        {
            foreach (string fcfldName in kvp.Value)
            {
                Debug.Print("\t{0}", fcfldName);
            }
        }
        else
            Debug.Print("\tUNUSED DOMAIN!");
    }
}

private Dictionary<string, List<string>> SummarizeDomains(string fgdPath)
{
    var ws = Open(fgdPath);
    var dict = InitDict(ws);

    var enumDs1 = ws.get_Datasets(esriDatasetType.esriDTAny);
    IDataset ds;
    while ((ds = enumDs1.Next()) != null)
    {
        Debug.Print("processing {0}", ds.Name);
        if (ds is IObjectClass)
            LoadDomains((IObjectClass)ds, dict);
        else if (ds is IFeatureDataset)
        {
            var enumDs2 = ds.Subsets;
            enumDs2.Reset();
            IDataset ds2;
            while ((ds2 = enumDs2.Next()) != null)
            {
                if (ds2 is IObjectClass)
                    LoadDomains((IObjectClass)ds2, dict);
            }
        }
    }
    return dict;
}
private void LoadDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
{
    if (oc is ISubtypes && ((ISubtypes)oc).HasSubtype)
        LoadSubtypeDomains(oc, dict);
    else
    {
        for (int i = 0; i < oc.Fields.FieldCount; i++)
        {
            var fld = oc.Fields.get_Field(i);
            if (fld.Domain == null)
                continue;
            if (dict.ContainsKey(fld.Domain.Name))
                dict[fld.Domain.Name].Add(String.Format("{0}.{1}",((IDataset)oc).Name,fld.Name));
            else
                throw new Exception("domain not found: " + fld.Domain.Name);
        }
    }
}
private void LoadSubtypeDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
{
    ISubtypes subTypes = oc as ISubtypes;
    var enumSubtypes = subTypes.Subtypes;
    enumSubtypes.Reset();
    int code;
    string stName;
    while ((stName = enumSubtypes.Next(out code)) != null)
    {
        for (int i = 0; i < oc.Fields.FieldCount; i++)
        {
            string fldName = oc.Fields.get_Field(i).Name;
            var domain = subTypes.get_Domain(code, fldName);
            if (domain != null)
            {
                if (dict.ContainsKey(domain.Name))
                    dict[domain.Name].Add(String.Format("{0}.{1}.{2}",stName,((IDataset)oc).Name,fldName));
                else
                    throw new Exception("domain not found: " + domain.Name);
            }
        }
    }
}
private Dictionary<string, List<string>> InitDict(IWorkspace ws)
{
    var dict = new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase);
    var enumDomain = ((IWorkspaceDomains)ws).Domains;
    enumDomain.Reset();
    IDomain d = null;
    while ((d = enumDomain.Next()) != null)
        dict.Add(d.Name, new List<string>());
    return dict;
}

private IWorkspace Open(string fgdbPath)
{
    Type t = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
    var wsf = Activator.CreateInstance(t) as IWorkspaceFactory;
    return wsf.OpenFromFile(fgdbPath, 0);
}

хоча перелік невикористаних доменів є корисним, це зворотна проблема, яку потрібно вирішити. Я насправді шукав "який FC використовує домен X?" (тому я можу видалити посилання та зробити домен невикористаним доменом). ((Я досі не пробував код, я просто продовжую назву функції))
matt wilkie

@matt о, так, це має сенс. Я змінив код, щоб показати, як це зробити.
Кірк Куйкендалл

е-е, можливо, це має бути повноцінним питанням, але де я поставити цей код? Я не можу знайти еквівалент v10 редактора VBA ( Інструменти-> Макроси-> Візуальний базовий редактор ).
matt wilkie

Вам потрібно буде встановити Visual Studio Express (безкоштовно) або новішу версію та ArcGIS SDK . Щойно ви зробите це, ви зможете дотримуватися цього покрокового інструкції для створення командної кнопки , а потім скопіюйте та вставте мій код у подію Click. Вам також потрібно буде додати відповідні посилання на проект.
Кірк Куйкендалл

5

Цей код повинен повертати запитання. Він буде швидко проходити всі класи та таблиці функцій у робочій області GDB / FS та повертати всі поля, пов’язані з доменом, іменем поля та класом характеристик / таблицею, до якого він належить.

import os
import arcpy
lst=[]
for dirpath,dirnames,files in arcpy.da.Walk( # the path to your workspace
, datatype=["FeatureClass","Table"]):
     for file in files:
         lst.append(os.path.join(dirpath,file))
for i in lst:
     for fld in arcpy.ListFields(i):
         if fld.domain != "":
             print os.path.basename(i),fld.name, fld.domain 

4

На жаль, відповідь Брайана, яка є прямою та корисною відповіддю на поставлене запитання, не вирішує мою актуальну проблему. Я припускаю, що під час роботи в gdb є помилка (хоча до жодного класу функцій не додані домени, все одно є видалений мені недоступний). У будь-якому випадку я знайшов інший метод для визначення того, які fc мають асоційовані домени. Це інтерактивне, але набагато швидше, ніж перегляд кожного властивості поля на кожному fc:

Перетягуйте пучки fc з проблемного gdb на інший gdb та перевірте діалогове вікно передачі даних . Пов’язані домени атрибутів, якщо такі є, будуть внизу списку. Повторюйте в менших і менших пучках, поки ви не звузите, який @ $% ## fc доставить вам важкий час.

нарешті звузилися до 2 FC, пов'язаних із реєстром домену


Цікаво, що навіть якщо говорить про те, що "drag-n-drop" HD_148009_2пов'язано Permanencyз реєстром CV , архівний сценарій Брайана повідомляє про не пов'язаний домен, а також інспектор полів властивостей Feature Class в ArcCatalog. Однак зараз я остаточно звузив його, щоб записати повідомлення про помилку за допомогою технічної підтримки Esri.
matt wilkie

4

Це те, що я думаю, що Метт Вілкі повинен був шукати і писати, щоб збільшити код Брайана. Мені довелося отримати всі домени для таблиць, класи функцій у кореневому каталозі бази даних та функції у всіх наборах даних функцій. Я експортував цю інформацію як csv, щоб дозволити деяким іншим працівникам очистити наше середовище бази даних від старих доменів.

def domainInfo(csvExportFolder):
    import arcpy,csv,os

    fcTabList = []
    list = []

    #Set workspace environment to geodatabase
    arcpy.env.workspace = r"H:\GIS\SDEConnections\Admin\Infrastructure.sde"

    #Prepping the csv
    csvFile = csv.writer(open(csvExportFolder+"\\"+ "Infrastructure Domains" + ".csv","wb"),delimiter = "|")
    csvFile.writerow(["FeatureDataSet","FeatureClass","FieldName","Domain"])

    #Get list of all features in geodatabase
    fdsList = arcpy.ListDatasets()
    fcs = arcpy.ListFeatureClasses()
    tbs = arcpy.ListTables()

    for fds in fdsList:
        fcs = arcpy.ListFeatureClasses("","",fds)
        if len(fcs) != 0:
            for fc in fcs:
                fcTabList.append([fds,fc])

    for fc in fcs:
        fcTabList.append([None,fc])

    for tb in tbs:
        fcTabList.append([None,tb])

    # Loop through all features in the database list
    for item in fcTabList:
        fds = item[0]
        fc = item[1]
        # List fields in feature class
        fields = arcpy.ListFields(fc)

        # Loop through fields
        for field in fields:

            # Check if field has domain
            if field.domain != "":

                # Print feature class, field, domain name
                csvFile.writerow([fds,fc,field.name,field.domain])

def main():
    csvExportFolder = r"H:\GIS"
    domainInfo(csvExportFolder)

if __name__ == "__main__":
    main()

0

Esri: FAQ: Як я можу знайти всі місця, на які посилаються домени в моїй базі даних геоданих? . "Функції Python, які можуть перераховувати властивості цих структур в базі даних геоданих. Серед властивостей є посилання на домени. Наведено зразок сценарію та базу даних geodata, які демонструють, як функції Python можуть використовуватися для переліку доменів та інших властивостей класів функцій та Домени можуть бути пов’язані з полями класу характеристик або таблиці; вони можуть бути додатково встановлені для полів, класифікованих за підтипом. "

Результати цього питання шуміть, виходять за рамки використовуваних доменів, але це широка платформа для початку роботи.

Executing: ParseDomainReferences [...]

fc at root level: Pt1
  fld OBJECTID
  fld SHAPE
  fld Field_Text, domain [Pets]
  fld Field_Long
  fld Field_Short, domain [Counts]
  fld Field_Double, domain [Ratios]
[...]
Subtype Code: 1
subCode: ('Default', False)
subCode: ('Name', u'One')
subCode: ('SubtypeField', u'Field_Long')
FieldValues
fldName: Field_Double, default: [no default], domain: Ratios
fldName: OBJECTID, default: [no default], domain: [no domain]
fldName: Field_Long, default: [no default], domain: [no domain]
fldName: Field_Short, default: 1, domain: Counts
fldName: SHAPE, default: [no default], domain: [no domain]
fldName: Field_Text, default: N, domain: [no domain]
[...etc]

Витяг з коду, відредагований для стислості:

def ParseFieldList (fc, fcPath):
...
      for fld in fldList:
        if fld.domain != None:
          if fld.domain != "":
...
        arcpy.AddMessage ("  fld " + fld.name + s)

      # get subtype list
      subDict = arcpy.da.ListSubtypes (fcPath)
      if len (subDict) > 0:
        for stCode in subDict.iteritems():
...
          valkey, vallist = stCode
          arcpy.AddMessage ("Subtype Code: {0}".format(valkey))
          i = 0
          for subCode in vallist.iteritems():
            i += 1
            if i < 4:
              arcpy.AddMessage ("subCode: {0}".format(subCode))
            else:
              fldkey, fldlist = subCode
              arcpy.AddMessage (fldkey)
              for fld in fldlist.iteritems():
...
                if dom != None:
                  s2 = dom.name
                arcpy.AddMessage ("fldName: " + fldName + ", default: " + s1 + ", domain: " + s2)
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.