ArcGIS Pro 3.7 API Reference Guide
ArcGIS.Core.Data.Knowledge Namespace / KnowledgeGraph Class / GetPropertyNameInfo Method
Example

In This Topic
    GetPropertyNameInfo Method
    In This Topic
    Gets the object containing the unique identifier property names in this knowledge graph. This method must be called on the MCT. Use QueuedTask.Run.
    Syntax
    Public Function GetPropertyNameInfo() As KnowledgeGraphPropertyInfo
    public KnowledgeGraphPropertyInfo GetPropertyNameInfo()

    Return Value

    Exceptions
    ExceptionDescription
    This method or property must be called within the lambda passed to QueuedTask.Run.
    Example
    Get the KG Provenance using KnowledgeGraphPropertyInfo
    {
      await QueuedTask.Run(() =>
      {
        //Create a connection properties
        var kg_props =
            new KnowledgeGraphConnectionProperties(new Uri(url));
        using (var kg = new KnowledgeGraph(kg_props))
        {
          // use the KnowledgeGraphPropertyInfo
          var propInfo = kg.GetPropertyNameInfo();
          var supportsProvenance = propInfo.SupportsProvenance;
          var provenanceType = propInfo.ProvenanceTypeName;
          var provenanceInfo = propInfo.ProvenancePropertyInfo;
        }
      });
    }
    Get the KG Document info using KnowledgeGraphPropertyInfo
    {
      await QueuedTask.Run(() =>
      {
        //Create a connection properties
        var kg_props =
            new KnowledgeGraphConnectionProperties(new Uri(url));
        using (var kg = new KnowledgeGraph(kg_props))
        {
          // use the KnowledgeGraphPropertyInfo
          var propInfo = kg.GetPropertyNameInfo();
          var supportsDocs = propInfo.SupportsDocuments;
          var documentType = propInfo.DocumentTypeName;
          var hasDocumentType = propInfo.HasDocumentTypeName; // available at Pro 3.6 only
          var documentInfo = propInfo.DocumentPropertyInfo;
        }
      });
    }
    Create a new Relationship and New Entities 1
    {
      var mv = MapView.Active;
      var create_rel1 = await QueuedTask.Run(() =>
      {
        //This example uses a chained edit operation
        var edit_op = new EditOperation()
        {
          Name = "Create entities and a relationship",
          SelectNewFeatures = true
        };
    
        //We are just going to use the GDB objects in this one but
        //we could equally use feature layers/standalone tables
    
        //using Feature Class/Tables (works within Investigation or map)
        var org_fc = kg.OpenDataset<FeatureClass>("Organization");
        var person_tbl = kg.OpenDataset<Table>("Person");
        //Relationship table
        var emp_tbl = kg.OpenDataset<Table>("HasEmployee");
    
        var attribs = new Dictionary<string, object>();
    
        //New Organization
        attribs["Name"] = "Acme Ltd.";
        attribs["Description"] = "Specializes in household items";
        attribs["SHAPE"] = mv.Extent.Center;//whatever is its location
    
        //Add it to the operation - we need the rowtoken
        var rowtoken = edit_op.Create(org_fc, attribs);
    
        attribs.Clear();//we are going to re-use the dictionary
    
        //New Person
        attribs["Name"] = "Bob";
        attribs["Age"] = "41";
        attribs["Skills"] = "Plumbing, Framing, Flooring";
    
        //Add it to the operation
        var rowtoken2 = edit_op.Create(person_tbl, attribs);
    
        attribs.Clear();
    
        //At this point we must execute the create of the entities
        if (edit_op.Execute())
        {
          //if we are here, the create of the entities was successful
    
          //Next, "chain" a second create for the relationship - this ensures that
          //Both creates (entities _and_ relation) will be -undone- together if needed
          //....in other words they will behave as if they are a -single- transaction
          var edit_op_rel = edit_op.CreateChainedOperation();
    
          //we need the names of the origin and destination relation properties
          var kg_prop_info = kg.GetPropertyNameInfo();
          //use the row tokens we held on to from the entity creates
          attribs[kg_prop_info.OriginIDPropertyName] = rowtoken.GlobalID;
          attribs[kg_prop_info.DestinationIDPropertyName] = rowtoken2.GlobalID;
    
          //Add any extra attribute information for the relation as needed
          attribs["StartDate"] = new DateTimeOffset(DateTime.Now);
    
          //Do the create of the relate
          edit_op_rel.Create(emp_tbl, attribs);
          return edit_op_rel.Execute();
        }
        return false;//Create of entities failed
      });
    }
    Create a Provenance Record
    {
      await QueuedTask.Run(() =>
      {
        //Instantiate an operation for the Create
        var edit_op = new EditOperation()
        {
          Name = "Create a new provenance record",
          SelectNewFeatures = true
        };
    
        //lets get the provenance table (provenance is not added to the
        //map TOC)
        var provenance_tbl = kg.OpenDataset<Table>("Provenance");
        if (provenance_tbl == null)
          return;
        //we will add a row to the provenance for person entity
        var person_tbl = kg.OpenDataset<Table>("Person");
    
        //Arbitrarily retrieve the first "person" row
        var instance_id = Guid.Empty;
        using (var rc = person_tbl.Search())
        {
          if (!rc.MoveNext())
            return;
          instance_id = rc.Current.GetGlobalID();//Get the global id
        }
    
        //Define the provenance attributes - we need the names
        //of the provenance properties from the KG ProvenancePropertyInfo
        var kg_prop_info = kg.GetPropertyNameInfo();
        var attribs = new Dictionary<string, object>();
        var ppi = kg_prop_info.ProvenancePropertyInfo;
    
        attribs[ppi.ProvenanceTypeNamePropertyName] =
            person_tbl.GetDefinition().GetName();//entity type name
        attribs[ppi.ProvenanceFieldNamePropertyName] = "name";//Must be a property/field on the entity
        attribs[ppi.ProvenanceSourceNamePropertyName] = "Annual Review 2024";//can be anything - can be null
                                                                             //note: Source type is controlled by the CodedValueDomain "esri__provenanceSourceType"
        attribs[ppi.ProvenanceSourceTypePropertyName] = "Document";//one of ["Document", "String", "URL"].
        attribs[ppi.ProvenanceSourcePropertyName] = "HR records";//can be anything, not null
        attribs[ppi.ProvenanceCommentPropertyName] = "Rock star";//can be anything - can be null
    
        //Add in the id of the provenance owner - our "person" in this case
        attribs[ppi.ProvenanceInstanceIDPropertyName] = instance_id;
    
        //Specify any additional custom attributes added to the provenance
        //schema by the user as needed....
        //attribs["custom_attrib"] = "Foo";
        //attribs["custom_attrib2"] = "Bar";
    
        //Create the provenance row
        edit_op.Create(provenance_tbl, attribs);
        if (edit_op.Execute())
        {
          //TODO: Operation succeeded
        }
      });
    }
    Create a Provenance Record 2
    {
      await QueuedTask.Run(() =>
      {
        // check if provenance supported
        var propInfo = kg.GetPropertyNameInfo();
        if (!propInfo.SupportsProvenance)
          return;
    
        //Instantiate an operation for the Create
        var edit_op = new EditOperation()
        {
          Name = "Create a new provenance record",
          SelectNewFeatures = true
        };
    
        var provName = propInfo.ProvenanceTypeName;
    
        //we will add a row to the provenance for person entity
        var person_tbl = kg.OpenDataset<Table>("Person");
    
        //Arbitrarily retrieve the first "person" row
        var instance_id = Guid.Empty;
        using (var rc = person_tbl.Search())
        {
          if (!rc.MoveNext())
            return;
          instance_id = rc.Current.GetGlobalID();//Get the global id
        }
    
        var originHandle = new RowHandle(person_tbl, instance_id);
        var pd = new KnowledgeGraphProvenanceDescription(
          originHandle, "name", KnowledgeGraphSourceType.Document,
          "Annual Review 2024", "HR records", "Rock star");
    
        //Create the provenance row
        edit_op.Create(pd);
        if (edit_op.Execute())
        {
          //TODO: Operation succeeded
        }
    
      });
    }
    Create a Document Record 1
    {
      var ok = await QueuedTask.Run(() =>
      {
        using (var kg_for_doc = kgLayer.GetDatastore())
        {
          var edit_op = new EditOperation()
          {
            Name = "Create Document Example",
            SelectNewFeatures = true
          };
    
          var doc_entity_name = GetDocumentTypeName(kg_for_doc.GetDataModel());
          if (string.IsNullOrEmpty(doc_entity_name))
            return false;
          var hasdoc_rel_name = GetHasDocumentTypeName(kg_for_doc.GetDataModel());
          if (string.IsNullOrEmpty(hasdoc_rel_name))
            return false;
    
          //Document can also be FeatureClass
          var doc_tbl = kg_for_doc.OpenDataset<Table>(doc_entity_name);
          var doc_rel_tbl = kg_for_doc.OpenDataset<Table>(hasdoc_rel_name);
    
          //This is the document to be added...file, image, resource, etc.
          var doc_url = @"E:\Data\Temp\HelloWorld.txt";
          var text = System.IO.File.ReadAllText(url);
    
          //Set document properties
          var attribs = new Dictionary<string, object>();
          attribs["contentType"] = @"text/plain";
          attribs["name"] = System.IO.Path.GetFileName(url);
          attribs["url"] = doc_url;
          //Add geometry if relevant
          //attribs["Shape"] = doc_location;
    
          //optional
          attribs["fileExtension"] = System.IO.Path.GetExtension(doc_url);
          attribs["text"] = System.IO.File.ReadAllText(doc_url);
    
          //optional and arbitrary - your choice
          attribs["title"] = System.IO.Path.GetFileNameWithoutExtension(doc_url);
          attribs["keywords"] = @"text,file,example";
          attribs["metadata"] = "";
    
          //Specify any additional custom attributes added to the document
          //schema by the user as needed....
          //attribs["custom_attrib"] = "Foo";
          //attribs["custom_attrib2"] = "Bar";
    
          //Get the entity whose document this is...
          var org_fc = kg_for_doc.OpenDataset<FeatureClass>("Organization");
          var qf = new ArcGIS.Core.Data.QueryFilter()
          {
            WhereClause = "name = 'Acme'",
            SubFields = "*"
          };
          var origin_org_id = Guid.Empty;
          using (var rc = org_fc.Search(qf))
          {
            if (!rc.MoveNext())
              return false;
            origin_org_id = rc.Current.GetGlobalID();//For the relate
          }
    
          //Create the document row/feature
          var rowtoken = edit_op.Create(doc_tbl, attribs);
          if (edit_op.Execute())
          {
            //Create the relationship row
            attribs.Clear();
            //we need the names of the origin and destination relation properties
            var kg_prop_info = kg_for_doc.GetPropertyNameInfo();
            //Specify the origin entity (i.e. the document 'owner') and
            //the document being related to (i.e. the document 'itself')
            attribs[kg_prop_info.OriginIDPropertyName] = origin_org_id;//entity
            attribs[kg_prop_info.DestinationIDPropertyName] = rowtoken.GlobalID;//document
    
            //Specify any custom attributes added to the has document
            //schema by the user as needed....
            //attribs["custom_attrib"] = "Foo";
            //attribs["custom_attrib2"] = "Bar";
    
            //"Chain" a second create for the relationship - this ensures that
            //Both creates (doc _and_ "has doc" relation) will be -undone- together if needed
            //....in other words they will behave as if they are a -single- transaction
            var edit_op_rel = edit_op.CreateChainedOperation();
            edit_op_rel.Create(doc_rel_tbl, attribs);
            return edit_op_rel.Execute();
          }
          return false;
        }
      });
    }
    
    string GetDocumentTypeName(KnowledgeGraphDataModel kg_dm)
    {
      var entity_types = kg_dm.GetEntityTypes();
      foreach (var entity_type in entity_types)
      {
        var role = entity_type.Value.GetRole();
        if (role == KnowledgeGraphNamedObjectTypeRole.Document)
          return entity_type.Value.GetName();
      }
      return "";
    }
    
    string GetHasDocumentTypeName(KnowledgeGraphDataModel kg_dm)
    {
      var rel_types = kg_dm.GetRelationshipTypes();
      foreach (var rel_type in rel_types)
      {
        var role = rel_type.Value.GetRole();
        if (role == KnowledgeGraphNamedObjectTypeRole.Document)
          return rel_type.Value.GetName();
      }
      return "";
    }
    Create a Document Record 2
    {
      await QueuedTask.Run(() =>
      {
        using (var kg_for_doc = kgLayer.GetDatastore())
        {
          var propInfo = kg_for_doc.GetPropertyNameInfo();
          if (!propInfo.SupportsDocuments)
            return false;
    
          var edit_op = new EditOperation()
          {
            Name = "Create Document Example",
            SelectNewFeatures = true
          };
    
          var doc_entity_name = propInfo.DocumentTypeName;
          var hasdoc_rel_name = GetHasDocumentTypeName(kg.GetDataModel());
    
          //Document can also be FeatureClass
          var doc_tbl = kg_for_doc.OpenDataset<Table>(doc_entity_name);
          var doc_rel_tbl = kg_for_doc.OpenDataset<Table>(hasdoc_rel_name);
    
          //This is the document to be added...file, image, resource, etc.
          var doc_url = @"E:\Data\Temp\HelloWorld.txt";
    
          // create the KnowledgeGraphDocumentDescription
          var kgDocDesc = new KnowledgeGraphDocumentDescription(doc_url);
    
          // if there is a geometry use the following ctor
          // var kgDocDesc = new KnowledgeGraphDocumentDescription(doc_url, doc_location);
    
          // if you have additional custom attributes 
          //var customDocAtts = new Dictionary<string, object>();
          //customDocAtts.Add("custom_attrib", "Foo");
          //customDocAtts.Add("custom_attrib2", "Bar");
          //var kgDocDesc = new KnowledgeGraphDocumentDescription(url, null, customDocAtts);
    
          // add additional properties if required
          kgDocDesc.Keywords = @"text,file,example";
    
          // The Create method will auto-populate the Url, Name, FileExtension and contentType fields of the document row
          // from the path supplied.  
          var rowToken = edit_op.Create(doc_tbl, kgDocDesc);
    
          //Get the entity whose document this is...
          var org_fc = kg_for_doc.OpenDataset<FeatureClass>("Organization");
          var qf = new ArcGIS.Core.Data.QueryFilter()
          {
            WhereClause = "name = 'Acme'",
            SubFields = "*"
          };
          var origin_org_id = Guid.Empty;
          using (var rc = org_fc.Search(qf))
          {
            if (!rc.MoveNext())
              return false;
            origin_org_id = rc.Current.GetGlobalID();//For the relate
          }
    
          // set up the row handles
          var originHandle = new RowHandle(org_fc, origin_org_id);    // entity
          var destinationHandle = new RowHandle(rowToken);            // document
    
          // create the KnowledgeGraphRelationshipDescription
          var rd = new KnowledgeGraphRelationshipDescription(originHandle, destinationHandle);
    
          // if you have additional custom attributes for the "HasDocument" relationship
          //var customHasDocAtts = new Dictionary<string, object>();
          //customHasDocAtts.Add("custom_attrib", "Foo");
          //customHasDocAtts.Add("custom_attrib2", "Bar");
          //var rd = new KnowledgeGraphRelationshipDescription(originHandle, destinationHandle, customHasDocAtts);
    
          // create the relate record using the same edit operation
          edit_op.Create(doc_rel_tbl, rd);
    
          //Call execute to create all the entities and relationship rows _together_
          return edit_op.Execute();
        }
      });
    }
    Modify an Entity and Relationship record
    {
      var mv = MapView.Active;
      await QueuedTask.Run(() =>
      {
        var edit_op = new EditOperation()
        {
          Name = "Modify an Entity and Relationship record",
          SelectModifiedFeatures = true
        };
    
        //We are  going to use mapmembers in this example
        //we could equally use feature classes/tables
        var kg_layer = mv.Map.GetLayersAsFlattenedList()?
                      .OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();
        //Entity
        var org_fl = kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>()
                        .First(child_layer => child_layer.Name == "Organization");
        //and/or Relationship
        var rel_stbl = kg_layer.GetStandaloneTablesAsFlattenedList()
                        .First(child_layer => child_layer.Name == "HasEmployee");
    
        //Get the entity feature to modify
        long org_oid = -1;
        var org_gid = Guid.Empty;
        var qf = new ArcGIS.Core.Data.QueryFilter()
        {
          WhereClause = "name = 'Acme'",
          SubFields = "*"
        };
        using (var rc = org_fl.Search(qf))
        {
          if (!rc.MoveNext())
            return;
          org_oid = rc.Current.GetObjectID();
          org_gid = rc.Current.GetGlobalID();
        }
        if (org_oid == -1)
          return; //nothing to modify
    
        var attribs = new Dictionary<string, object>();
    
        //Specify attributes to be updated
        attribs["Name"] = "Acme Ltd.";
        attribs["Description"] = "Specializes in household items";
        attribs["SHAPE"] = mv.Extent.Center;
    
        //Add to the edit operation
        edit_op.Modify(org_fl, org_oid, attribs);
    
        //Get the relationship record (if a relate is being updated)
        //we need the name of the origin id property
        var kg_prop_info = kg.GetPropertyNameInfo();
        var sql = $"{kg_prop_info.OriginIDPropertyName} = ";
        sql += "'" + org_gid.ToString("B").ToUpper() + "'";
    
        qf = new ArcGIS.Core.Data.QueryFilter()
        {
          WhereClause = sql,
          SubFields = "*"
        };
        long rel_oid = -1;
        using (var rc = rel_stbl.Search(qf))
        {
          if (!rc.MoveNext())
            return;
          rel_oid = rc.Current.GetObjectID();
        }
        if (rel_oid > -1)
        {
          //add the relate row updates to the edit operation
          attribs.Clear();//we are going to re-use the dictionary
          attribs["StartDate"] = new DateTimeOffset(DateTime.Now);
          attribs["custom_attrib"] = "Foo";
          attribs["custom_attrib2"] = "Bar";
          //Add to the edit operation
          edit_op.Modify(rel_stbl, rel_oid, attribs);
        }
        //do the update(s)
        if (edit_op.Execute())
        {
          //TODO: Operation succeeded
        }
    
      });
    }
    Create a new Relationship from Existing Entities 1
    {
      var create_rel = await QueuedTask.Run(() =>
      {
        //Instantiate an operation for the Create
        var edit_op = new EditOperation()
        {
          Name = "Create a new relationship record",
          SelectNewFeatures = true
        };
    
        //Use datasets or feature layer(s) or standalone table(s)
        //Get a reference to the KnowledgeGraph
        //var kg = ... ; 
    
        //We will use a relate called 'HasEmployee' to relate an Organization w/ a Person
        //Use either tables or map members to get the rows to be related...
        var org_fc = kg.OpenDataset<FeatureClass>("Organization");
        var person_tbl = kg.OpenDataset<Table>("Person");
    
        //Get the relationship dataset
        //We can use either a table or standalone table
        var emp_tbl = kg.OpenDataset<Table>("HasEmployee");
    
        //we need the names of the origin and destination relationship properties
        var kg_prop_info = kg.GetPropertyNameInfo();
    
        //Arbitrarily use the first record from the two entity datasets "to be" related
        //Entities are always related by Global ID. Origin to Destination specifies the
        //direction (of the relate).
        //
        //Populate the attributes for the relationship
        var attribs = new Dictionary<string, object>();
    
        using (var rc = org_fc.Search())
        {
          if (rc.MoveNext())
            //Use the KnowledgeGraphPropertyInfo to avoid hardcoding...
            attribs[kg_prop_info.OriginIDPropertyName] = rc.Current.GetGlobalID();
        }
        using (var rc = person_tbl.Search())
        {
          if (rc.MoveNext())
            //Use the KnowledgeGraphPropertyInfo to avoid hardcoding...
            attribs[kg_prop_info.DestinationIDPropertyName] = rc.Current.GetGlobalID();
        }
    
        //Add any extra attribute information for the relation as needed
        attribs["StartDate"] = new DateTimeOffset(DateTime.Now);
    
        //Add a create for the relationship to the operation
        edit_op.Create(emp_tbl, attribs);
    
        //Do the create
        return edit_op.Execute();
      });
    }
    Requirements

    Target Platforms: Windows 11 Home, Pro, Enterprise (64 bit)

    ArcGIS Pro version: 3.4 or higher.
    See Also