Liệt kê các lớp tính năng với các miền hoạt động?


18

Tôi có một cơ sở dữ liệu địa lý tệp Esri với các miền thuộc tính được xác định. Tôi cần xóa một số miền thuộc tính nhưng không thể vì "Miền được sử dụng theo quy tắc thuộc tính". . Làm thế nào tôi có thể khám phá (các) lớp tính năng đang sử dụng các tên miền?

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)

Có hơn một trăm lớp tính năng trong cơ sở dữ liệu địa lý, tương tác nhìn vào các thuộc tính trường FC cho mỗi lớp là không bắt đầu. Gdb quá lớn để chuyển đổi thành gdb cá nhân và đi vào cửa sau với quyền truy cập ms (dù sao cũng là một phương thức tinh ranh).


(2011 -5 -5): Một cách khác để diễn đạt điều này là "Lớp tính năng nào đang sử dụng miền X?"


Bạn đang sử dụng tên miền phụ?
Kirk Kuykendall

@kirk, vâng, có một kiểu con, nhưng các miền tôi đang cố xóa không sử dụng kiểu con
matt wilkie

1
Trong trường hợp đó tôi nghĩ mã của Brian sẽ hoạt động.
Kirk Kuykendall

1
@kirk, chỉnh sửa: Tôi không nghĩ rằng tôi đã sử dụng các kiểu con + tên miền, nhưng sau nhiều lần lột xác và mở một trường hợp hỗ trợ kỹ thuật, hóa ra tôi thực sự đã sử dụng một tên miền. Đó là lễ hội nhấp chuột thực sự để xác định cuplrit cụ thể còn lại. Tôi nên đầu tư nhiều thời gian hơn để theo dõi phương pháp c # của bạn!
matt wilkie

Câu trả lời:


3

Để trả lời câu hỏi xử lý các lớp tính năng với các kiểu con, có thể với 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))

Mã loại phụ, mã hóa, sẽ bằng 0 nếu không có loại phụ, vì vậy mã sẽ in ra 'Không'.

Các từ điển phân nhóm đã nhiều đến nó, vì vậy kiểm tra nó trong mã.


Thay đổi câu trả lời được chấp nhận của tôi cho câu hỏi này. Nó ngắn và trực tiếp. Phiên bản mã của tôi tại github.com/envygeo/arcplus/blob/master/ArcToolbox/Scripts/ ,. Cảm ơn!
matt wilkie

21

Python có các phương thức để liệt kê các lớp đối tượng trong cơ sở dữ liệu địa lý, lặp qua từng lớp đối tượng trong danh sách, liệt kê các trường trong từng lớp đối tượng và hiển thị miền của từng trường.

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

Đoạn mã trên sẽ hoạt động trong ArcGIS 10 và nó sẽ in một danh sách ngay trong cửa sổ trình thông dịch python. Sau đó, bạn có thể sao chép và dán danh sách vào trình soạn thảo văn bản hoặc Excel để xem lại kết quả dễ dàng hơn.


Điều này cũng sẽ xử lý các tên miền phụ?
Kirk Kuykendall

Tôi không chắc chắn nếu điều này sẽ xử lý các kiểu con hoặc tên miền phụ. Tôi chưa bao giờ sử dụng các kiểu con trước đây. Nếu có một tên miền được gán cho một trường cụ thể, tên miền sẽ được in.
Brian

thật đẹp, cảm ơn Brian. Ban đầu nó không hoạt động với tôi, nhưng cuối cùng tôi đã nhớ rằng listFC không tái diễn trong FeatureDatasets mà không cần thêm trợ giúp ( gis.stackexchange.com/questions/5893/ .). Tất cả đều tốt ngay bây giờ! :)
matt wilkie

@Kirk, không, nó không thấy các kiểu con sử dụng tên miền.
matt wilkie

Thực hiện theo ví dụ resource.arcgis.com/en/help/main/10.1/index.html#// Đối để đi qua tất cả các kiểu con và tên miền liên quan của chúng.
Michael Promotionson

8

Vì tôi không nghĩ python xử lý các kiểu con, nên tôi sẽ đăng mã c # này. Tôi đã thử nghiệm nó với geodb nước / nước thải mẫu của Esri và tìm thấy các lĩnh vực không được sử dụng sau đây:

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

Thông thường các DBA cảm thấy khó chịu khi các tên miền - về cơ bản là các bảng tra cứu - không thể được truy cập thông qua SQL.

Mã này được kiểm tra từ arcmap ( được cập nhật theo nhận xét của 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);
}

trong khi liệt kê các tên miền không sử dụng là hữu ích, đây là nghịch đảo của vấn đề cần giải quyết. Tôi đã thực sự tìm kiếm "FC nào đang sử dụng tên miền X?" (vì vậy tôi có thể xóa liên kết và đặt tên miền thành tên miền không sử dụng). ((Tôi vẫn chưa thử mã, tôi chỉ sử dụng tên của hàm))
matt wilkie

@matt oh, vâng, điều đó có ý nghĩa. Tôi đã thay đổi mã để chỉ ra cách làm điều đó.
Kirk Kuykendall

uhh, có lẽ đây là một câu hỏi đầy đủ, nhưng, tôi phải đặt mã này ở đâu? Tôi không thể xác định vị trí tương đương v10 của trình soạn thảo VBA ( cụ-> Macro-> Visual Basic Editor ).
matt wilkie

Bạn sẽ cần cài đặt Visual Studio Express (miễn phí) hoặc cao hơn và ArcGIS SDK . Khi bạn đã thực hiện điều đó, bạn sẽ có thể làm theo hướng dẫn này để tạo nút lệnh , sau đó sao chép và dán mã của tôi vào sự kiện Click. Bạn cũng sẽ cần thêm các tài liệu tham khảo phù hợp cho dự án.
Kirk Kuykendall

5

Mã này sẽ trả về những gì đang được yêu cầu. Nó sẽ đi qua tất cả các lớp và bảng tính năng trong không gian làm việc GDB / FS và trả về tất cả các trường được liên kết với một tên miền, tên trường và lớp / bảng tính năng mà nó thuộc về.

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

Thật không may, câu trả lời của Brian, một câu trả lời trực tiếp và có thể sử dụng được cho câu hỏi, không giải quyết được vấn đề thực sự của tôi. Tôi đoán là do có lỗi trong gdb (mặc dù không có lớp tính năng nào có tên miền được đính kèm, nhưng vẫn có một lỗi tôi không được phép xóa). Trong mọi trường hợp, tôi đã tìm thấy một phương pháp khác để xác định fc nào có các miền liên quan. Nó tương tác, nhưng nhiều nhanh hơn so với đi qua mỗi tài sản lĩnh vực trên tất cả các fc duy nhất:

Kéo và thả các bó fc từ vấn đề gdb sang gdb khác và kiểm tra hộp thoại Truyền dữ liệu . Các miền thuộc tính được liên kết, nếu có, sẽ ở cuối danh sách. Lặp lại trong các bó nhỏ hơn và nhỏ hơn cho đến khi bạn thu hẹp mà @ $% ## fc đang mang lại cho bạn một khoảng thời gian khó khăn.

cuối cùng đã thu hẹp xuống còn 2 FC được liên kết với một miền CV


Thật kỳ lạ, mặc dù kéo-n-drop nói HD_148009_2được liên kết với Miền CV Permanency, tập lệnh phức tạp của Brian báo cáo không có miền được liên kết và trình kiểm tra các trường thuộc tính của lớp tính năng trong ArcCatalog cũng không. Tuy nhiên, bây giờ tôi cuối cùng đã thu hẹp nó xuống đủ để ghi lại một báo cáo lỗi với bộ phận hỗ trợ kỹ thuật của Esri.
matt wilkie

3

Đây là những gì tôi tưởng tượng Matt Wilkie đã phải tìm kiếm và viết để tăng mã của Brian. Tôi đã phải lấy tất cả các tên miền cho các bảng, các lớp đối tượng trong thư mục gốc của cơ sở dữ liệu và các tính năng trong tất cả các bộ dữ liệu tính năng. Tôi đã xuất thông tin dưới dạng csv để cho phép một số công nhân khác dọn sạch môi trường cơ sở dữ liệu địa lý của các miền cũ.

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: Làm cách nào tôi có thể tìm thấy tất cả các địa điểm nơi các tên miền được tham chiếu trong cơ sở dữ liệu địa lý của tôi? . "Các hàm Python có thể liệt kê các thuộc tính của các cấu trúc này trong cơ sở dữ liệu địa lý. Trong số các thuộc tính là các miền được tham chiếu. Tập lệnh mẫu và cơ sở dữ liệu địa lý tệp được cung cấp để chứng minh cách các hàm Python có thể được sử dụng để liệt kê các miền và các thuộc tính khác của các lớp đối tượng và bảng. Tên miền có thể được liên kết với các trường trong một lớp tính năng hoặc bảng, chúng cũng có thể được đặt cho các trường được phân loại theo một kiểu con. "

Kết quả gây ồn ào cho câu hỏi này, vượt ra ngoài những tên miền đang được sử dụng, nhưng là nền tảng rộng hơn để bắt đầu.

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]

Đoạn trích mã, được chỉnh sửa cho ngắn gọn:

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)
...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.