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(); });
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 });
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; }); }
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 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"] = org_updated_location; //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 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 } });
Target Platforms: Windows 11, Windows 10