¿Listado de clases de entidad con dominios activos?

18

Tengo una geodatabase de archivos Esri con dominios de atributo definido Necesito eliminar algunos de los dominios de atributo, pero no puedo porque "El dominio está siendo usado por una regla de atributo". ¿Cómo puedo descubrir qué clase de entidad (es) está usando los dominios?

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)

Hay más de un centenar de clases de entidades en la geodatabase, mirando de forma interactiva las propiedades del campo FC, ya que cada una no tiene inicio. El gdb es demasiado grande para convertirlo en un gdb personal e ir por la puerta trasera con ms-access (un método poco fiable de todos modos).

(2011-May-26): Otra forma de expresar esto es "¿Qué clase de entidad está usando el dominio X?"

    
pregunta matt wilkie 19.05.2011 - 20:07

6 respuestas

4

Desafortunadamente, la respuesta de Brian, que es una respuesta directa y útil a la pregunta, no resuelve mi problema real. Supongo que debido a un error en el gdb en cuestión (a pesar de que ninguna de las clases de entidad tiene dominios adjuntos, todavía hay uno que no puedo eliminar). En cualquier caso, encontré otro método para determinar qué fc tienen dominios asociados. Es interactivo, pero mucho más rápido que ir a través de cada propiedad de campo en cada fc:

  

Arrastra y suelta grupos de fc desde   Problema gdb a otro gdb e inspeccionar   el diálogo Transferencia de datos . Vinculado   los dominios de atributo, si los hay, estarán en   la parte inferior de la lista. Repetir en   racimos cada vez más pequeños hasta que   reducir lo que @ $% ## fc está dando   usted es un momento difícil.

    
respondido por el matt wilkie 20.05.2011 - 00:58
21

Python tiene métodos para listar clases de entidad en una geodatabase, recorrer cada clase de entidad en la lista, listar campos en cada clase de entidad y mostrar el dominio de cada campo.

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

El código anterior debería funcionar en ArcGIS 10 e imprimirá una lista en la ventana del intérprete de python. Luego puede copiar y pegar la lista en un editor de texto o Excel para revisar los resultados más fácilmente.

    
respondido por el Brian 19.05.2011 - 21:12
8

Como no creo que Python maneje subtipos, estoy publicando este código c # que debería. Lo probé con geodb de aguas residuales / aguas residuales de Esri y encontré los siguientes dominios no utilizados:

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

A menudo, a los administradores de bases de datos les molesta que no se pueda acceder a los dominios, que son esencialmente tablas de búsqueda, a través de SQL.

Este código probado desde arcmap ( actualizado según el comentario de 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);
}
    
respondido por el Kirk Kuykendall 20.05.2011 - 00:59
4

Este código debe devolver lo que se solicita. Recorrerá sucintamente todas las clases de entidad y tablas en un área de trabajo GDB / FS y devolverá todos los campos asociados con un dominio, el nombre del campo y la clase de entidad / tabla a la que pertenece.

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 
    
respondido por el COCO 05.10.2016 - 02:28
3

Esto es lo que imagino que Matt Wilkie tuvo que buscar y escribir para aumentar el código de Brian. Tenía que obtener todos los dominios para tablas, clases de entidad en el directorio raíz de una base de datos y características en todos los conjuntos de datos de características. Exporté la información como CSV para permitir que otros trabajadores limpien nuestros entornos de geodatabase de dominios antiguos.

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()
    
respondido por el René Casiano 03.06.2016 - 17:49
3

Para responder a la pregunta de cómo manejar clases de entidad con subtipos, es posible con 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))

El código del subtipo, stcode, será cero si no hay subtipos, por lo que el código imprime "Ninguno".

El diccionario de subtipos tiene más que eso, así que inspeccionarlo en el código.

    
respondido por el Richard Morgan 16.11.2016 - 13:00

Lea otras preguntas en las etiquetas