KnowledgeGraphRelationshipType Class
Represents a relationship type in the knowledge graph.
Check Whether A Graph Type has a Spatial Property
//Use GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm) from
//the 'Get Whether KG Has a Document Type' snippet to
//get the documentNameType parameter
protected bool HasGeometry(KnowledgeGraphNamedObjectType kg_named_obj)
{
var props = kg_named_obj.GetProperties();
return props.Any(prop => prop.FieldType == FieldType.Geometry);
}
Get KnowledgeGraph Relationship Types
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var dict_types = kg_dm.GetRelationshipTypes();
foreach (var kvp in dict_types)
{
var rel_type = kvp.Value;
var role = rel_type.GetRole();
//note "name" will be the same name as the corresponding
//feature class or table in the KG's relational gdb model
var name = rel_type.GetName();
//etc.
//Get relationship end points
var end_points = rel_type.GetEndPoints();
foreach (var end_point in end_points)
{
System.Diagnostics.Debug.WriteLine(
$"Origin: '{end_point.GetOriginEntityTypeName()}', " +
$"Destination: '{end_point.GetDestinationEntityTypeName()}'");
}
}
}
}
});
Create a new Relationship and New Entities 1
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"] = org_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 new Relationship and New Entities 2
var createRel = await QueuedTask.Run(() =>
{
//This example uses a KnowledgeGraphRelationshipDescription
var edit_op = new EditOperation()
{
Name = "Create entities and a relationship using a KG relate desc",
SelectNewFeatures = true
};
//We are just 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();
//From the KG Layer get the relevant child feature layer(s) and/or standalone
//table(s)
var org_fl = kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>()
.First(child_layer => child_layer.Name == "Organization");
var person_stbl = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "Person");
var rel_stbl = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "HasEmployee");
var attribs = new Dictionary<string, object>();
//New Organization
attribs["Name"] = "Acme Ltd.";
attribs["Description"] = "Specializes in household items";
attribs["SHAPE"] = org_location;
//Add it to the operation - we need the rowtoken
var rowtoken_org = edit_op.Create(org_fl, 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 rowtoken_person = edit_op.Create(person_stbl, attribs);
attribs.Clear();
//Create the new relationship using a KnowledgeGraphRelationshipDescription
//Row handles act as the placeholders for the TO BE created new entities that will
//be related
var src_row_handle = new RowHandle(rowtoken_org);
var dest_row_handle = new RowHandle(rowtoken_person);
//Add any extra attribute information for the relation as needed
attribs["StartDate"] = new DateTimeOffset(DateTime.Now);
var rel_desc = new KnowledgeGraphRelationshipDescription(
src_row_handle, dest_row_handle, attribs);
//Add the relate description to the edit operation
edit_op.Create(rel_stbl, rel_desc);
//Execute the create of the entities and relationship
return edit_op.Execute();
});
Create a Document Record
internal static 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 "";
}
internal static 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 "";
}
internal async void AddDocumentRecord()
{
await QueuedTask.Run(() =>
{
using (var kg = GetKnowledgeGraph())
{
var edit_op = new EditOperation()
{
Name = "Create Document Example",
SelectNewFeatures = true
};
var doc_entity_name = GetDocumentTypeName(kg.GetDataModel());
if (string.IsNullOrEmpty(doc_entity_name))
return false;
var hasdoc_rel_name = GetHasDocumentTypeName(kg.GetDataModel());
if (string.IsNullOrEmpty(hasdoc_rel_name))
return false;
//Document can also be FeatureClass
var doc_tbl = kg.OpenDataset<Table>(doc_entity_name);
var doc_rel_tbl = kg.OpenDataset<Table>(hasdoc_rel_name);
//This is the document to be added...file, image, resource, etc.
var 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"] = url;
//Add geometry if relevant
//attribs["Shape"] = doc_location;
//optional
attribs["fileExtension"] = System.IO.Path.GetExtension(url);
attribs["text"] = System.IO.File.ReadAllText(url);
//optional and arbitrary - your choice
attribs["title"] = System.IO.Path.GetFileNameWithoutExtension(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.OpenDataset<FeatureClass>("Organization");
var qf = new 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.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;
});
}
Delete an Entity record
await QueuedTask.Run(() =>
{
var edit_op = new EditOperation()
{
Name = "Delete an Entity record"
};
//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");
//Get the entity feature(s) to delete
long org_oid = -1;
var qf = new QueryFilter()
{
WhereClause = "name = 'Acme'",
SubFields = "*"
};
using (var rc = org_fl.Search(qf))
{
if (!rc.MoveNext())
return;//nothing to delete
org_oid = rc.Current.GetObjectID();
}
edit_op.Delete(org_fl, org_oid);
edit_op.Execute();//Do the delete
});
Delete a Relationship record 1
await QueuedTask.Run(() =>
{
var edit_op = new EditOperation()
{
Name = "Delete a Relationship record"
};
//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();
//Relationship
var rel_stbl = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "HasEmployee");
//Get the relation row to delete
long rel_oid = -1;
using (var rc = rel_stbl.Search())
{
if (!rc.MoveNext())
return;
//arbitrarily, in this example, get the first row
rel_oid = rc.Current.GetObjectID();
}
edit_op.Delete(rel_stbl, rel_oid);
edit_op.Execute();//Do the delete
});
Delete a Relationship record 2
await QueuedTask.Run(() =>
{
var edit_op = new EditOperation()
{
Name = "Delete a Relationship record"
};
//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();
//entities
var entityOrg = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "Organization");
var entityPerson = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "Person");
//Relationship
var rel_stbl = kg_layer.GetStandaloneTablesAsFlattenedList()
.First(child_layer => child_layer.Name == "HasEmployee");
// get the origin, destination records
Guid guidOrigin = Guid.Empty;
Guid guidDestination = Guid.Empty;
using (var rc = entityOrg.Search())
{
if (rc.MoveNext())
//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...
guidOrigin = rc.Current.GetGlobalID();
}
using (var rc = entityPerson.Search())
{
if (rc.MoveNext())
//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...
guidDestination = rc.Current.GetGlobalID();
}
var rd = new KnowledgeGraphRelationshipDescription(guidOrigin, guidDestination);
edit_op.Delete(rel_stbl, rd);
edit_op.Execute();//Do the delete
});
Target Platforms: Windows 11, Windows 10
ArcGIS Pro version: 3.2 or higher.