활성 도메인이있는 기능 클래스를 나열 하시겠습니까?


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)

지오 데이터베이스에는 100 개가 넘는 피쳐 클래스가 있으며 각각의 FC 필드 속성을 대화식으로 보면 스타터가 아닙니다. gdb가 너무 커서 개인 gdb로 변환 할 수 없으며 ms-access (어쨌든 dodgy 방법)를 사용하여 뒷문으로 들어갑니다.


(2011-5 월 26 일) : 이를 표현하는 또 다른 방법은 "어떤 기능 클래스가 도메인 X를 사용하고 있습니까?"입니다.


하위 도메인을 사용하고 있습니까?
커크 Kuykendall

@kirk, 그래이 하위 유형입니다,하지만 난 제거에 노력하고있어 도메인은 하위 유형 사용하지 않는
매트 윌키

1
이 경우 Brian의 코드가 작동한다고 생각합니다.
커크 Kuykendall

1
@ 커크, 수정 : 하위 유형 + 도메인을 사용하고 있다고 생각 하지 않았지만 기술 지원 사례를 많이 열어보고 실제로 실제로 하나를 사용하고있는 것으로 나타났습니다. 남은 특정 큐 틀릿을 식별하는 것은 진정한 클릭 페스트였습니다. 나는 당신의 C # 방법에 대한 후속 조치에 더 많은 시간을 투자했을 것입니다!
매트 윌키

답변:


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는 0이되므로 코드는 '없음'을 인쇄합니다.

아형 사전은 더 그것 때문에 코드를 검사하고있다.


이것에 대한 내 대답을 변경합니다. 짧고 직접적입니다. 내 코드 버전은 github.com/envygeo/arcplus/blob/master/ArcToolbox/Scripts/…에 있습니다. 감사!
매트 윌키

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에서 작동하며 파이썬 인터프리터 창에 바로 목록을 인쇄합니다. 그런 다음 목록을 복사하여 텍스트 편집기 나 Excel에 붙여 넣어 결과를보다 쉽게 ​​검토 할 수 있습니다.


하위 유형 도메인도 처리합니까?
커크 Kuykendall

이것이 하위 유형 또는 하위 유형 도메인을 처리하는지 확실하지 않습니다. 이전에 하위 유형을 사용한 적이 없습니다. 특정 필드에 도메인이 할당 된 경우 도메인 이름이 인쇄됩니다.
Brian

감사합니다 브라이언 처음에 나를 위해 일을하지 않았다, 그러나 결국 나는 listFC 몇 가지 추가적인 도움 (없이 FeatureDatasets에 재귀하지 않는 것을 기억 gis.stackexchange.com/questions/5893/... ). 이제 모두 좋아! :)
matt wilkie

@ Kirk, 아니요 도메인을 사용하는 하위 유형이 표시되지 않습니다.
matt wilkie 22.48에

resources.arcgis.com/en/help/main/10.1/index.html#//… 예제를 따라 모든 하위 유형과 관련 도메인을 살펴 봅니다.
Michael Stimson

8

파이썬이 하위 유형을 처리한다고 생각하지 않기 때문에이 C # 코드를 게시하고 있습니다. Esri의 샘플 water / wastewater geodb로 테스트 한 결과 다음 미사용 도메인이 발견되었습니다.

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을 통해 액세스 할 수 없다는 사실에 짜증을냅니다.

이 코드는 arcmap에서 테스트되었습니다 ( Matt의 설명에 따라 업데이트 됨 ).

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를 사용하고 있습니까?"를 찾고있었습니다. (링크를 제거 하고 도메인을 사용하지 않는 도메인으로 만들 수 있습니다). ((난 아직도 난 그냥) 함수의 이름에 갈거야, 코드를 시도하지 않은)
매트 윌키

@ 맷 오, 그래, 그 말이 맞아. 그 방법을 보여주기 위해 코드를 변경했습니다.
커크 Kuykendall

어쩌면 이것은 본격적인 질문이어야하지만이 코드는 어디에 두어야합니까? VBA 편집기 ( Tools-> Macros-> Visual Basic Editor ) 와 동등한 v10을 찾을 수 없습니다 .
matt wilkie

Visual Studio Express (무료) 이상과 ArcGIS SDK 를 설치해야합니다 . 이 작업을 완료하면이 연습 을 따라 명령 단추 를 만든 다음 내 코드를 복사하여 Click 이벤트에 붙여 넣을 수 있습니다. 또한 프로젝트에 대한 적절한 참조를 추가해야합니다.
Kirk Kuykendall

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

불행히도 Brian의 대답은 질문에 직접적이고 유용한 대답으로 실제 문제를 해결하지 못합니다. gdb에 버그가 있다고 생각합니다 (어떤 기능 클래스에도 도메인이 연결되어 있지 않더라도 삭제할 수없는 도메인이 있습니다). 어쨌든 어떤 fc가 도메인을 연결했는지 확인하는 다른 방법을 찾았습니다. 대화식이지만 모든 단일 FC에서 각 필드 속성을 통과하는 것보다 훨씬 빠릅니다.

문제 gdb에서 다른 gdb로 fc를 끌어다 놓고 데이터 전송 대화 상자를 검사하십시오 . 연결된 속성 도메인 (있는 경우)이 목록의 맨 아래에 있습니다. @ $ % ## fc가 어려움을 겪는 범위를 좁힐 때까지 작고 작은 묶음으로 반복하십시오.

CV 도메인에 연결된 2 개의 FC로 좁혀 짐


흥미롭게도, 끌어서 놓기 기능 HD_148009_2이 CV 도메인에 연결되어 있다고하더라도 PermanencyBrian의 arcpy 스크립트는 연결된 도메인을보고하지 않으며 ArcCatalog의 기능 클래스 속성 필드 관리자도보고하지 않습니다. 그러나 이제 Esri 기술 지원을 통해 버그 보고서를 기록 할 수있을 정도로 좁혔습니다.
매트 윌키

4

이것이 Matt Wilkie가 Brian의 코드를 보강하기 위해 조회하고 작성해야한다고 상상 한 것입니다. 테이블의 모든 도메인, 데이터베이스의 루트 디렉토리에있는 기능 클래스 및 모든 기능 데이터 세트의 기능을 가져와야했습니다. 다른 작업자가 이전 도메인의 지리 데이터베이스 환경을 정리할 수 있도록 정보를 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 함수 도메인. 피처 클래스 또는 테이블의 필드와 도메인을 연관시킬 수 있으며 하위 유형별로 분류 된 필드에 대해 추가로 설정할 수 있습니다. "

사용중인 도메인을 넘어서서이 질문에 대한 결과는 시끄럽지 만 시작을위한 더 넓은 플랫폼입니다.

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)
...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.