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.
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.
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());
}
}
});
Target Platforms: Windows 11, Windows 10
ArcGIS Pro version: 3.4 or higher.