การแสดงคลาสคุณลักษณะด้วยโดเมนที่ใช้งานอยู่?


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-May-26):อีกวิธีหนึ่งในวลีนี้คือ "Class Feature ใดที่ใช้โดเมน X"


คุณกำลังใช้โดเมนย่อย
Kirk Kuykendall

@kirk ใช่มี subtype แต่โดเมนที่ฉันพยายามลบไม่ได้ใช้ subtype
matt wilkie

1
ในกรณีนี้ฉันคิดว่ารหัสของ Brian ทำงานได้
Kirk Kuykendall

1
@kirk, การแก้ไข: ฉันไม่คิดว่าฉันใช้ subtypes + domains แต่หลังจากที่มีการล้อเลียนและเปิดกรณีสนับสนุนทางเทคนิคมากมันกลับกลายเป็นว่าฉันใช้มันจริง ๆ มันเป็นจริงคลิก -FEST เพื่อระบุ Cuplrit ที่เหลือโดยเฉพาะ ฉันควรใช้เวลามากขึ้นในการติดตามวิธี 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 จะเป็นศูนย์หากไม่มีประเภทย่อยดังนั้นรหัสจะพิมพ์ 'ไม่มี'

พจนานุกรมเชื้อได้มากขึ้นไปเพื่อให้ตรวจสอบได้ในรหัส


เปลี่ยนคำตอบที่ฉันยอมรับให้เป็นคำตอบนี้ มันสั้นและตรง รุ่นของฉันรหัสของคุณที่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 เพื่อตรวจสอบผลลัพธ์ได้ง่ายขึ้น


สิ่งนี้จะจัดการโดเมนย่อยด้วยหรือไม่
Kirk Kuykendall

ฉันไม่แน่ใจว่าสิ่งนี้จะจัดการกับประเภทย่อยหรือโดเมนย่อย ฉันไม่เคยใช้ชนิดย่อยมาก่อน หากมีโดเมนที่กำหนดให้กับเขตข้อมูลเฉพาะชื่อโดเมนจะถูกพิมพ์
Brian

สวยขอบคุณไบรอัน เริ่มแรกมันไม่ได้ผลสำหรับฉัน แต่ในที่สุดฉันจำได้ว่า listFC ไม่สามารถเรียกคืน FeatureDatasets ได้หากไม่มีความช่วยเหลือเพิ่มเติม ( gis.stackexchange.com/questions/5893/ … ) ตอนนี้ดีแล้ว! :)
matt wilkie

@Kirk ไม่เห็นประเภทย่อยโดยใช้โดเมน
matt wilkie

ทำตามตัวอย่างresources.arcgis.com/th/help/main/10.1/index.html#//…เพื่อดูชนิดย่อยทั้งหมดและโดเมนที่เกี่ยวข้อง
Michael Stimson

8

เนื่องจากฉันไม่คิดว่าหลามจัดการกับชนิดย่อยฉันจึงโพสต์รหัส c # นี้ที่ควร ฉันทดสอบด้วย Geodb น้ำ / ตัวอย่างน้ำเสียของ 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

รหัสนี้ทดสอบจาก 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 อยู่หรือไม่" (ดังนั้นฉันอาจลบลิงค์และทำให้โดเมนเป็นโดเมนที่ไม่ได้ใช้) ((ฉันยังไม่ได้ลองรหัสฉันเพิ่งจะไปที่ชื่อของฟังก์ชั่น))
แมตต์ wilkie

@ แมตต์ใช่ใช่ว่าเหมาะสม ฉันเปลี่ยนรหัสเพื่อแสดงวิธีการทำ
Kirk Kuykendall

เอ่อบางทีนี่อาจเป็นคำถามที่เต็มไปหมด แต่ฉันจะวางรหัสนี้ที่ไหน ฉันไม่สามารถหาตำแหน่งเทียบเท่า v10 ของตัวแก้ไข VBA ( เครื่องมือ -> Macros-> ตัวแก้ไข Visual Basic )
matt wilkie

คุณจะต้องติดตั้ง Visual Studio เอ็กซ์เพรส (ฟรี) หรือมากขึ้นและArcGIS SDK เมื่อคุณทำอย่างนั้นแล้วคุณควรจะสามารถปฏิบัติตามคำแนะนำนี้เพื่อสร้างปุ่มคำสั่งจากนั้นคัดลอกและวางรหัสของฉันลงในเหตุการณ์คลิก คุณจะต้องเพิ่มการอ้างอิงที่เหมาะสมกับโครงการ
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

น่าเสียดายที่คำตอบของไบรอันซึ่งเป็นคำตอบที่ตรงและสามารถใช้งานได้ตามคำถามที่ถามไม่สามารถแก้ปัญหาที่แท้จริงของฉันได้ ฉันเชื่อว่ามีข้อผิดพลาดใน gdb ที่อยู่ในมือ (แม้ว่าจะไม่มีคลาสที่ติดตั้งโดเมน แต่ก็ยังมีอีกหนึ่งที่ฉันไม่ได้รับอนุญาตให้ลบ) ไม่ว่าในกรณีใดฉันพบวิธีอื่นในการพิจารณาว่า fc มีโดเมนที่เกี่ยวข้องหรือไม่ มันเป็นแบบโต้ตอบ แต่มากเร็วกว่าจะผ่านคุณสมบัติแต่ละเขตในทุก fc เดียว:

ลากและวางพวงของ fc จากปัญหา gdb ไปยัง gdb อื่นและตรวจสอบไดอะล็อกการถ่ายโอนข้อมูล โดเมนแอตทริบิวต์ที่เชื่อมโยง (ถ้ามี) จะอยู่ที่ด้านล่างของรายการ ทำซ้ำในพวงที่เล็กกว่าและเล็กกว่าจนกว่าคุณจะแคบลงว่า @ $% ## fc ให้เวลากับคุณอย่างไร

ในที่สุดก็แคบลงเหลือ 2 FC ที่เชื่อมโยงกับโดเมน CV


อยากรู้อยากเห็นแม้ว่า drag-n-drop บอกว่าHD_148009_2มีการเชื่อมโยงไปยังโดเมน CV Permanency, สคริปต์ arcpy ของ Brian รายงานว่าไม่มีโดเมนที่เชื่อมโยงและทั้งผู้ตรวจสอบคุณสมบัติฟีเจอร์คลาสคุณสมบัติใน ArcCatalog อย่างไรก็ตามในตอนนี้ฉันก็แคบลงพอที่จะบันทึกรายงานข้อผิดพลาดด้วยการสนับสนุนด้านเทคนิคของ Esri
matt wilkie

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: คำถามที่พบบ่อย: ฉันจะค้นหาสถานที่ทั้งหมดที่มีการอ้างอิงโดเมนในฐานข้อมูลภูมิศาสตร์ของฉันได้อย่างไร ."ฟังก์ชั่น Python ที่สามารถแสดงรายการคุณสมบัติของโครงสร้างเหล่านี้ในฐานข้อมูล geod ในบรรดาคุณสมบัติคือโดเมนที่อ้างอิงสคริปต์ตัวอย่างและฐานข้อมูลไฟล์มีการจัดเตรียมไว้เพื่อสาธิตวิธีการใช้งานฟังก์ชัน 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.