ArcGIS Pro 3.4 API Reference Guide
ArcGIS.Desktop.Mapping Namespace / KnowledgeGraphExtensions Class / ApplySchemaEdits Method
The knowledge graph "this" extension method parameter
The schema builder with the enqueued operations to be executed
Example

In This Topic
    ApplySchemaEdits Method
    In This Topic
    Addins should use the knowledge graph ApplySchemaEdits() call to execute enqueued schema operations on ArcGIS.Core.Data.DDL.SchemaBuilder rather than ArcGIS.Core.Data.DDL.SchemaBuilder.Build. This method must be called on the MCT. Use QueuedTask.Run.
    Syntax
    public static bool ApplySchemaEdits( 
       KnowledgeGraph kg,
       SchemaBuilder schemaBuilder
    )
    Public Shared Function ApplySchemaEdits( _
       ByVal kg As KnowledgeGraph, _
       ByVal schemaBuilder As SchemaBuilder _
    ) As Boolean

    Parameters

    kg
    The knowledge graph "this" extension method parameter
    schemaBuilder
    The schema builder with the enqueued operations to be executed

    Return Value

    true if the schema edits were successfully applied.
    Exceptions
    ExceptionDescription
    schemaBuilder cannot be null
    This method or property must be called within the lambda passed to QueuedTask.Run.
    Remarks
    To ensure proper refresh of the application UI when making schema changes to a knowledge graph, instead of calling schemaBuilder.Build(), addins should instead execute the enqueued schema operations with a kg.ApplySchemaEdits(schemaBuilder) call. This ensures that the map, link chart, or investigation UI (whichever is active) will refresh correctly after the schema edits have been applied.
    Schema operations will fail if ApplySchemaEdits is called whenever an edit session is active on the knowledge graph.
    Schema edits will still be applied if an addin uses schemaBuilder.Build() but the application UI may be inconsistent after the schema edits have been completed and need to be manually refreshed, or, in some cases, the active view or even project, closed and re-opened.
    Example
    Create Entity and Relationship Types with SchemaBuilder
    await QueuedTask.Run(() =>
    {
      using (var kg = GetKnowledgeGraph())
      {
        if (kg == null)
          return;
    
        var entity_name = "PhoneCall";
        var relate_name = "WhoCalledWho";
    
        //Entity Fields
        var descs1 =
            new List<KnowledgeGraphPropertyDescription>();
        descs1.Add(
          new KnowledgeGraphPropertyDescription("PhoneOwner", FieldType.String));
        descs1.Add(
          new KnowledgeGraphPropertyDescription("PhoneNumber", FieldType.String));
        descs1.Add(
          new KnowledgeGraphPropertyDescription("LocationID", FieldType.BigInteger));
        descs1.Add(
          new KnowledgeGraphPropertyDescription("DateAndTime", FieldType.Date));
    
        //Relate Fields
        var descs2 =
            new List<KnowledgeGraphPropertyDescription>();
        descs2.Add(
          new KnowledgeGraphPropertyDescription("Foo", FieldType.String));
        descs2.Add(
          new KnowledgeGraphPropertyDescription("Bar", FieldType.String));
    
    
        var includeShape = true;//change to false to omit the shape column
        var hasZ = false;
        var hasM = false;
    
        KnowledgeGraphEntityTypeDescription entityDesc = null;
        KnowledgeGraphRelationshipTypeDescription relateDesc = null;
        if (includeShape)
        {
          var sr = kg.GetSpatialReference();
          var shp_desc = new ShapeDescription(GeometryType.Point, sr)
          {
            HasM = hasM,
            HasZ = hasZ
          };
          entityDesc = new KnowledgeGraphEntityTypeDescription(
            entity_name, descs1, shp_desc);
          relateDesc = new KnowledgeGraphRelationshipTypeDescription(
            relate_name, descs2, shp_desc);
        }
        else
        {
          entityDesc = new KnowledgeGraphEntityTypeDescription(
            entity_name, descs1);
          relateDesc = new KnowledgeGraphRelationshipTypeDescription(
            relate_name, descs2);
        }
        //Run the schema builder
        try
        {
          SchemaBuilder sb = new(kg);
          sb.Create(entityDesc);
          sb.Create(relateDesc);
          //Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'
          //to refresh the Pro UI
          if (!kg.ApplySchemaEdits(sb))
          {
            var err_msg = string.Join(",", sb.ErrorMessages.ToArray());
            System.Diagnostics.Debug.WriteLine($"Entity/Relate Create error: {err_msg}");
          }
        }
        catch (Exception ex)
        {
          System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
      }
    });
    
    Delete Entity and Relationship Types with SchemaBuilder
    await QueuedTask.Run(() =>
    {
      using (var kg = GetKnowledgeGraph())
      {
        if (kg == null)
          return;
    
        var entity_name = "PhoneCall";
        var relate_name = "WhoCalledWho";
    
        var entityDesc = new KnowledgeGraphEntityTypeDescription(entity_name);
        var relateDesc = new KnowledgeGraphRelationshipTypeDescription(relate_name);
    
        //Run the schema builder
        try
        {
          SchemaBuilder sb = new(kg);
          sb.Delete(entityDesc);
          sb.Delete(relateDesc);
          //Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'
          //to refresh the Pro UI
          if (!kg.ApplySchemaEdits(sb))
          {
            var err_msg = string.Join(",", sb.ErrorMessages.ToArray());
            System.Diagnostics.Debug.WriteLine($"Entity/Relate Delete error: {err_msg}");
          }
        }
        catch (Exception ex)
        {
          System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
      }
    });
    
    Modify Entity and Relationship Type Schemas with SchemaBuilder
    await QueuedTask.Run(() =>
    {
      using (var kg = GetKnowledgeGraph())
      {
        if (kg == null)
          return;
    
        var entity_name = "PhoneCall";
        var relate_name = "WhoCalledWho";
    
        var kvp_entity = kg.GetDataModel().GetEntityTypes()
             .First(r => r.Key == entity_name);
        var kvp_relate = kg.GetDataModel().GetRelationshipTypes()
                       .First(r => r.Key == relate_name);
    
        //Let's delete one field and add a new one from each
        //A field gets deleted implicitly if it is not included in the list of
        //fields - or "properties" in this case....so we will remove the last
        //property from the list
        var entity_props = kvp_entity.Value.GetProperties().Reverse().Skip(1).Reverse();
        var prop_descs = new List<KnowledgeGraphPropertyDescription>();
    
        foreach (var prop in entity_props)
        {
          if (prop.FieldType == FieldType.Geometry)
          {
            continue;//skip shape
          }
          var prop_desc = new KnowledgeGraphPropertyDescription(prop);
          prop_descs.Add(prop_desc);
        }
        //deal with shape - we need to keep it
        //SchemaBuilder deletes any field not included in the "modify" list
        ShapeDescription shape_desc = null;
        if (kvp_entity.Value.GetIsSpatial())
        {
          var geom_def = kvp_entity.Value.GetShapeDefinition();
          var shape_name = kvp_entity.Value.GetShapeField();
          shape_desc = new ShapeDescription(
            shape_name, geom_def.geometryType, geom_def.sr);
        }
        //add the new entity property
        prop_descs.Add(
          KnowledgeGraphPropertyDescription.CreateStringProperty("foo", 10));
        //make a description for the entity type - ok if shape_desc is null
        var entityDesc = new KnowledgeGraphEntityTypeDescription(
          entity_name, prop_descs, shape_desc);
    
        //Add the entity type description to the schema builder using 'Modify'
        SchemaBuilder sb = new(kg);
        sb.Modify(entityDesc);
    
        //Repeat for the relationship - assuming we have at least one custom attribute field
        //that can be deleted on our relationship schema...
        var rel_props = kvp_relate.Value.GetProperties().Reverse().Skip(1).Reverse();
        var rel_prop_descs = new List<KnowledgeGraphPropertyDescription>();
    
        foreach (var prop in rel_props)
        {
          if (prop.FieldType == FieldType.Geometry)
          {
            continue;//skip shape
          }
          var prop_desc = new KnowledgeGraphPropertyDescription(prop);
          rel_prop_descs.Add(prop_desc);
        }
        //deal with shape - we need to keep it
        //SchemaBuilder deletes any field not included in the "modify" list
        ShapeDescription shape_desc_rel = null;
        if (kvp_relate.Value.GetIsSpatial())
        {
          var geom_def = kvp_relate.Value.GetShapeDefinition();
          var shape_name = kvp_relate.Value.GetShapeField();
          shape_desc_rel = new ShapeDescription(
            shape_name, geom_def.geometryType, geom_def.sr);
        }
        //add a new relationship property
        rel_prop_descs.Add(
          KnowledgeGraphPropertyDescription.CreateStringProperty("bar", 10));
        //make a description for the relationship type - ok if shape_desc is null
        var relDesc = new KnowledgeGraphRelationshipTypeDescription(
          relate_name, rel_prop_descs, shape_desc_rel);
    
        //Add the relationship type description to the schema builder using 'Modify'
        sb.Modify(relDesc);
    
        //Run the schema builder
        try
        {
          //Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'
          //to refresh the Pro UI
          if (!kg.ApplySchemaEdits(sb))
          {
            var err_msg = string.Join(",", sb.ErrorMessages.ToArray());
            System.Diagnostics.Debug.WriteLine($"Entity/Relate Modify error: {err_msg}");
          }
        }
        catch (Exception ex)
        {
          System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
      }
    });
    
    Create Domain and Field Definition on KG Schemas with SchemaBuilder
        await QueuedTask.Run(() =>
        {
          using (var kg = GetKnowledgeGraph())
          {
            if (kg == null)
              return;
    
            var entity_name = "Fruit";
    
            //Domains are managed on the GDB objects...
            var fruit_fc = kg.OpenDataset<FeatureClass>(entity_name);
            var fruit_fc_def = fruit_fc.GetDefinition();
    
            var fieldFruitTypes = fruit_fc_def.GetFields()
                  .FirstOrDefault(f => f.Name == "FruitTypes");
            var fieldShelfLife = fruit_fc_def.GetFields()
                .FirstOrDefault(f => f.Name == "ShelfLife");
    
            //Create a coded value domain and add it to a new field
            var fruit_cvd_desc = new CodedValueDomainDescription(
              "FruitTypes", FieldType.String, 
              new SortedList<object, string> {
                              { "A", "Apple" },
                              { "B", "Banana" },
                              { "C", "Coconut" }
              })  {
                SplitPolicy = SplitPolicy.Duplicate,
                MergePolicy = MergePolicy.DefaultValue
            };
    
            //Create a Range Domain and add the domain to a new field description also
            var shelf_life_rd_desc = new RangeDomainDescription(
                                          "ShelfLife", FieldType.Integer, 0, 14);
    
            var sb = new SchemaBuilder(kg);
            sb.Create(fruit_cvd_desc);
            sb.Create(shelf_life_rd_desc);
    
            //Create the new field descriptions that will be associated with the
            //"new" FruitTypes coded value domain and the ShelfLife range domain
            var fruit_types_fld = new ArcGIS.Core.Data.DDL.FieldDescription(
                                          "FruitTypes", FieldType.String);
            fruit_types_fld.SetDomainDescription(fruit_cvd_desc);
    
            //ShelfLife will use the range domain
            var shelf_life_fld = new ArcGIS.Core.Data.DDL.FieldDescription(
    "ShelfLife", FieldType.Integer);
            shelf_life_fld.SetDomainDescription(shelf_life_rd_desc);
    
            //Add the descriptions to the list of field descriptions for the
            //fruit feature class - Modify schema needs _all_ fields to be included
            //in the schema, not just the new ones to be added.
            var fruit_fc_desc = new FeatureClassDescription(fruit_fc_def);
    
            var modified_fld_descs = new List<ArcGIS.Core.Data.DDL.FieldDescription>(
              fruit_fc_desc.FieldDescriptions);
    
            modified_fld_descs.Add(fruit_types_fld);
            modified_fld_descs.Add(shelf_life_fld);
    
            //Create a feature class description to modify the fruit entity
            //with the new fields and their associated domains
            var updated_fruit_fc =
              new FeatureClassDescription(entity_name, modified_fld_descs,
                                          fruit_fc_desc.ShapeDescription);
    
            //Add the modified fruit fc desc to the schema builder
            sb.Modify(updated_fruit_fc);
    
            //Run the schema builder
            try
            {
              if (!kg.ApplySchemaEdits(sb))
              {
                var err_msg = string.Join(",", sb.ErrorMessages.ToArray());
                System.Diagnostics.Debug.WriteLine($"Create domains error: {err_msg}");
              }
            }
            catch (Exception ex)
            {
              System.Diagnostics.Debug.WriteLine(ex.ToString());
            }
          }
        });
    
    Requirements

    Target Platforms: Windows 11, Windows 10

    ArcGIS Pro version: 3.4 or higher.
    See Also