stringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));try{//Open a connectionusing(varkg=new KnowledgeGraph(kg_props)){//TODO...use the KnowledgeGraph}}catch(GeodatabaseNotFoundOrOpenedExceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}});
Getting a Connection from a KnowledgeGraphLayer
varkgLayer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();
QueuedTask.Run(()=>{// use the layer directlyKnowledgeGraphdatastore= kgLayer.GetDatastore();// or you can use any of the sub items since//KnowledgeGraphLayer is a composite layer - get the first // child feature layer or standalone tablevarfeatlayer= kgLayer?.GetLayersAsFlattenedList()?.OfType<FeatureLayer>()?.FirstOrDefault();KnowledgeGraphkg=null;if(featlayer!=null){using(varfc= featlayer.GetFeatureClass())kg= fc.GetDatastore()as KnowledgeGraph;//TODO use KnowledgeGraph}else{//try standalone tablevarstbl= kgLayer?.GetStandaloneTablesAsFlattenedList()?.FirstOrDefault();if(stbl!=null){using(vartbl= stbl.GetTable())kg= tbl.GetDatastore()as KnowledgeGraph;//TODO use KnowledgeGraph}}});
Retrieving GDB FeatureClasses and Definitions
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=new KnowledgeGraph(kg_props)){//Get the featureclass definitions from the KG datastorevarfc_defs= kg.GetDefinitions<FeatureClassDefinition>();//For each feature class definition, get the corresponding//feature class. Note: The name of the feature class will match //the name of its corresponding KnowledgeGraph named object type//in the KnowledgeGraph graph data modelforeach(var fc_def in fc_defs){varfc_name= fc_def.GetName();using(varfc= kg.OpenDataset<FeatureClass>(fc_name)){//TODO - use the feature class}}}});
Retrieving GDB Tables and Definitions
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=new KnowledgeGraph(kg_props)){//Get the table definitions from the KG datastorevartbl_defs= kg.GetDefinitions<TableDefinition>();//For each table definition, get the corresponding//table. Note: The name of the table will match the name//of its corresponding KnowledgeGraph named object type in//the KnowledgeGraph graph data modelforeach(var tbl_def in tbl_defs){vartbl_name= tbl_def.GetName();using(varfc= kg.OpenDataset<Table>(tbl_name)){//TODO - use the table}}}});
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){//TODO use KG data model...}}});
Get Data Model Properties
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){varkg_name= System.IO.Path.GetFileName( System.IO.Path.GetDirectoryName(kg_props.URL.ToString())); System.Diagnostics.Debug.WriteLine($"\r\n'{kg_name}' Datamodel:\r\n-----------------");vartime_stamp= kg_dm.GetTimestamp();varsr= kg_dm.GetSpatialReference(); System.Diagnostics.Debug.WriteLine($"Timestamp: {time_stamp}"); System.Diagnostics.Debug.WriteLine($"Sref: {sr.Wkid}"); System.Diagnostics.Debug.WriteLine($"IsStrict: {kg_dm.GetIsStrict()}"); System.Diagnostics.Debug.WriteLine($"OIDPropertyName: {kg_dm.GetOIDPropertyName()}"); System.Diagnostics.Debug.WriteLine($"IsArcGISManaged: {kg_dm.GetIsArcGISManaged()}");}}});
Get Data Model Identifier Info
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){varkg_id_info= kg_dm.GetIdentifierInfo();varkg_id_gen= kg_id_info.GetIdentifierGeneration();if(kg_id_info is KnowledgeGraphNativeIdentifier kg_ni){ System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphNativeIdentifier");}elseif(kg_id_info is KnowledgeGraphUniformIdentifier kg_ui){ System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphUniformIdentifier"); System.Diagnostics.Debug.WriteLine($"IdentifierName: '{kg_ui.GetIdentifierName()}'");} System.Diagnostics.Debug.WriteLine($"Identifier MethodHint: {kg_id_gen.GetMethodHint()}");}}});
Get Data Model MetaEntityTypes/Provenance
//Provenance entity type is stored as a MetaEntityType
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){vardict_types= kg_dm.GetMetaEntityTypes();//If there is no provenance then MetaEntityTypes will be//an empty collectionforeach(var kvp in dict_types){varmeta_entity_type= kvp.Value;if(meta_entity_type.GetRole()== KnowledgeGraphNamedObjectTypeRole.Provenance){//TODO - use the provenance entity typevarname= meta_entity_type.GetName();}}}}});
Get Whether KG Supports Provenance
internalstringGetProvenanceEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types= kg_dm.GetMetaEntityTypes();foreach(var entity_type in entity_types){if(entity_type.Value.GetRole()== KnowledgeGraphNamedObjectTypeRole.Provenance)return entity_type.Value.GetName();}return"";}internalboolKnowledgeGraphSupportsProvenance(KnowledgeGraphkg){//if there is a provenance entity type then the KnowledgeGraph//supports provenancereturn!string.IsNullOrEmpty(
GetProvenanceEntityTypeName(kg.GetDataModel()));// OR use the KnowledgeGraphPropertyInfovarpropInfo= kg.GetPropertyNameInfo();return propInfo.SupportsProvenance;}
Get Whether KG Supports Provenance using KnowledgeGraphPropertyInfo
internalvoidKnowledgeGraphProvenance(KnowledgeGraphkg){// use the KnowledgeGraphPropertyInfovarpropInfo= kg.GetPropertyNameInfo();varsupportsProvenance= propInfo.SupportsProvenance;varprovenanceType= propInfo.ProvenanceTypeName;varprovenanceInfo= propInfo.ProvenancePropertyInfo;}
Get KnowledgeGraph Entity Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){vardict_types= kg_dm.GetEntityTypes();foreach(var kvp in dict_types){varentity_type= kvp.Value;varrole= entity_type.GetRole();//note "name" will be the same name as the corresponding//feature class or table in the KG's relational gdb modelvarname= entity_type.GetName();varalias= entity_type.GetAliasName();varobjectIDPropertyName= entity_type.GetObjectIDPropertyName();//etc}}}});
Get Whether KG Has a Document Type
internalstringGetDocumentEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types= kg_dm.GetEntityTypes();foreach(var entity_type in entity_types){varrole= entity_type.Value.GetRole();if(role== KnowledgeGraphNamedObjectTypeRole.Document)return entity_type.Value.GetName();}return"";//Unusual - probably Neo4j user-managed}internalboolKnowledgeGraphHasDocumentType(KnowledgeGraphkg){//uncommon for there not to be a document typereturn!string.IsNullOrEmpty(
GetDocumentEntityTypeName(kg.GetDataModel()));}
Check Whether A KG Entity Is a Document
//Use GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm) from//the 'Get Whether KG Has a Document Type' snippet to//get the documentNameType parameterprotectedboolGetEntityIsDocument(KnowledgeGraphEntityValueentity,stringdocumentNameType=""){if(string.IsNullOrEmpty(documentNameType))returnfalse;return entity.GetTypeName()==documentNameType;}
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 parameterprotectedboolHasGeometry(KnowledgeGraphNamedObjectTypekg_named_obj){varprops= kg_named_obj.GetProperties();return props.Any(prop => prop.FieldType == FieldType.Geometry);}
Get KnowledgeGraph Relationship Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){vardict_types= kg_dm.GetRelationshipTypes();foreach(var kvp in dict_types){varrel_type= kvp.Value;varrole= rel_type.GetRole();//note "name" will be the same name as the corresponding//feature class or table in the KG's relational gdb modelvarname= rel_type.GetName();//etc.//Get relationship end pointsvarend_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 KG Layer containing all Entity and Relate types
QueuedTask.Run(()=>{//With a connection to a KG established or source uri available...//Create a KnowledgeGraphLayerCreationParamsvarkg_params=new KnowledgeGraphLayerCreationParams(kg){Name="KG_With_All_Types",IsVisible=false};//Orvarkg_params2=new KnowledgeGraphLayerCreationParams(new Uri(url)){Name="KG_With_All_Types",IsVisible=false};//Call layer factory with map or group layer container. //A KG layer containing a feature layer and/or standalone table per//entity and relate type (except provenance) is createdvarkg_layer= LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>( kg_params, map);});
Create a KG Layer containing a subset of Entity and Relate types
QueuedTask.Run(()=>{//To create a KG layer (on a map or link chart) with a subset of//entities and relates, you must create an "id set". The workflow//is very similar to how you would create a SelectionSet.//First, create a dictionary containing the names of the types to be//added plus a corresponding list of ids (just like with a selection set).//Note: null or an empty list means add all records for "that" type..varkg_datamodel= kg.GetDataModel();//Arbitrarily get the name of the first entity and relate typevarfirst_entity= kg_datamodel.GetEntityTypes().Keys.First();varfirst_relate= kg_datamodel.GetRelationshipTypes().Keys.First();//Make entries in the dictionary for eachvardict=newDictionary<string,List<long>>(); dict.Add(first_entity,newList<long>());//Empty list means all records dict.Add(first_relate,null);//null list means all records//or specific records - however the ids are obtained//dict.Add(entity_or_relate_name, new List<long>() { 1, 5, 18, 36, 78});//Create the id set...varidSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict);//Create the layer params and assign the id setvarkg_params=new KnowledgeGraphLayerCreationParams(kg){Name="KG_With_ID_Set",IsVisible=false,IDSet=idSet};//Call layer factory with map or group layer container//A KG layer containing just the feature layer(s) and/or standalone table(s)//for the entity and/or relate types + associated records will be createdvarkg_layer= LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>( kg_params, map);});
Using LayerFactory.Instance.CanCreateLayer with KG Create Layer Params
QueuedTask.Run(()=>{//Feature class and/or standalone tables representing KG entity and//relate types can only be added to a map (or link chart) as a child//of a KnowledgeGraph layer....//For example:varfc= kg.OpenDataset<FeatureClass>("Some_Entity_Or_Relate_Name");try{//Attempting to create a feature layer containing the returned fc//NOT ALLOWED - can only be a child of a KG layervarfl_params_w_kg=new FeatureLayerCreationParams(fc);//CanCreateLayer will return falseif(!(LayerFactory.Instance.CanCreateLayer<FeatureLayer>( fl_params_w_kg, map))){ System.Diagnostics.Debug.WriteLine($"Cannot create a feature layer for {fc.GetName()}");return;}//This will throw an exception LayerFactory.Instance.CreateLayer<FeatureLayer>(fl_params_w_kg, map);}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}//Can only be added as a child of a parent KGvardict=newDictionary<string,List<long>>(); dict.Add(fc.GetName(),newList<long>());varkg_params=new KnowledgeGraphLayerCreationParams(kg){Name=$"KG_With_Just_{fc.GetName()}",IsVisible=false,IDSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict)};varkg_layer= LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>( kg_params, map);});
KnowledgeGraph Layer
Get and Set a KG Layer IDSet
varkg_layer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kg_layer==null)return;
QueuedTask.Run(()=>{//Get the existing kg layer id set and convert to a dictionaryvarlayer_id_set= kg_layer.GetIDSet();vardict= layer_id_set.ToOIDDictionary();//Empty list means all records//Create an id set from a dictionaryvardict2=newDictionary<string,List<long>>(); dict2.Add("Enity_Or_Relate_Type_Name1",null);//Null means all records dict2.Add("Enity_Or_Relate_Type_Name2",newList<long>());//Empty list means all records dict2.Add("Enity_Or_Relate_Type_Name3",newList<long>(){3,5,9,101,34});//Explicit list of ids//dict2.Add("Enity_Or_Relate_Type_Name4",// new List<long>() { etc, etc });//Create the id setvaridset= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict2);//Can be used to create a layer, link chart, append to link chart, etc...});
Is a dataset part of a Knowledge Graph
varfeatureLyer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();if(featureLyer==null)return;
QueuedTask.Run(()=>{//Get the feature classvarfc= featureLyer.GetFeatureClass();// is it part of a KnowledgeGraph?varisPartOfKG= fc.GetIsKnowledgeGraphDataset();});
Get KG Datastore
varkgLayer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;
QueuedTask.Run(()=>{// get the datastorevarkg= kgLayer.GetDatastore();// now submit a search or a query// kg.SubmitSearch// kg.SubmitQuery});
Get KG Service uri
kgLayer.GetServiceUri();
SubLayers of a KnowledgeGraph Layer
varmap= MapView.Active.Map;varkgLayer= map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;if(map.MapType == MapType.LinkChart){// if map is of MapType.LinkChart then the first level// children of the kgLayer are of type LinkChartFeatureLayervarchildLayers= kgLayer.Layers;foreach(var childLayer in childLayers){if(childLayer is LinkChartFeatureLayer lcFeatureLayer){varisEntity= lcFeatureLayer.IsEntity;varisRel= lcFeatureLayer.IsRelationship;// TODO - continue processing}}}elseif(map.MapType == MapType.Map){// if map is of MapType.Map then the children of the// kgLayer are the standard Featurelayer and StandAloneTablevarchidlren= kgLayer.GetMapMembersAsFlattenedList();foreach(var child in chidlren){if(child is FeatureLayer fl){// TODO - process the feature layer}elseif(child is StandaloneTable st){// TODO - process the standalone table}}}
Create a LinkChart from a subset of an existing LinkChart IDSet
varmap= MapView.Active.Map;if(map.MapType != MapType.LinkChart)return;// find the KG layervarkgLayer= map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;// find the first LinkChartFeatureLayer in the KG layervarlcFeatureLayer= kgLayer.GetLayersAsFlattenedList().OfType<LinkChartFeatureLayer>().FirstOrDefault();if(lcFeatureLayer!=null)return;
QueuedTask.Run(()=>{// get the KGvarkg= kgLayer.GetDatastore();// get the ID set of the KG layervaridSet= kgLayer.GetIDSet();// get the named object type in the KG that the LinkChartFeatureLayer representsvartypeName= lcFeatureLayer.GetTypeName();// if there are items in the ID Set for this typeif(idSet.Contains(typeName)){// build a new ID set containing only these recordsvardict= idSet.ToOIDDictionary();varoids= dict[typeName];varnewDict=newDictionary<string,List<long>>(); newDict.Add(typeName, oids);varnewIDSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, newDict);// now create a new link chart using just this subset of records MapFactory.Instance.CreateLinkChart("subset LinkChart", kg, newIDSet);}});
Graph Query and Text Search
Submit a Graph Query
//On the QueuedTask...//and assuming you have established a connection to a knowledge graph//...//Construct an openCypher query - return the first 10 entities (whatever//they are...)varquery="MATCH (n) RETURN n LIMIT 10";//default limit is 100 if not specified//other examples...//query = "MATCH (a:Person) RETURN [a.name, a.age] ORDER BY a.age DESC LIMIT 50";//query = "MATCH (b:Person) RETURN { Xperson: { Xname: b.name, Xage: b.age } } ORDER BY b.name DESC";//query = "MATCH p = (c:Person)-[:HasCar]-() RETURN p ORDER BY c.name DESC";//Create a query filter//Note: OutputSpatialReference is currently ignoredvarkg_qf=new KnowledgeGraphQueryFilter(){QueryText=query};//Optionally - u can choose to include provenance in the results//(_if_ the KG has provenance - otherwise the query will fail)if(includeProvenanceIfPresent){//see "Get Whether KG Supports Provenance" snippetif(KnowledgeGraphSupportsProvenance(kg)){//Only include if the KG has provenance
kg_qf.ProvenanceBehavior =
KnowledgeGraphProvenanceBehavior.Include;//default is exclude}}//submit the query - returns a KnowledgeGraphCursorusing(varkg_rc= kg.SubmitQuery(kg_qf)){//wait for rows to be returned from the server//note the "await"...while(await kg_rc.WaitForRowsAsync()){//Rows have been retrieved - process this "batch"...while(kg_rc.MoveNext()){//Get the current KnowledgeGraphRowusing(vargraph_row= kg_rc.Current){//Graph row is an array, process all returned values...varval_count=(int)graph_row.GetCount();for(inti=0;i<val_count;i++){varretval= graph_row[i];//Process row value (note: recursive)//See "Process a KnowledgeGraphRow Value" snippet
ProcessKnowledgeGraphRowValue(retval);}}}}//WaitForRowsAsync}//SubmitQuery
Submit a Text Search
//On the QueuedTask...//and assuming you have established a connection to a knowledge graph//...//Construct a KG search filter. Search text uses Apache Lucene Query Parser//syntax - https://lucene.apache.org/core/2_9_4/queryparsersyntax.htmlvarkg_sf=new KnowledgeGraphSearchFilter(){SearchTarget= KnowledgeGraphNamedTypeCategory.Entity,SearchText="Acme Electric Co.",ReturnSearchContext=true,MaxRowCount=10//Default is 100 if not specified};//submit the search - returns a KnowledgeGraphCursorvare=0;using(varkg_rc= kg.SubmitSearch(kg_sf)){//wait for rows to be returned from the server//note the "await"...while(await kg_rc.WaitForRowsAsync()){//Rows have been retrieved - process this "batch"...while(kg_rc.MoveNext()){//Get the current KnowledgeGraphRowusing(vargraph_row= kg_rc.Current){//We are returning entities from this searchvarentity= graph_row[0]as KnowledgeGraphEntityValue;varentity_type= entity.GetTypeName();varrecord=newList<string>();//discover keys(aka "fields") dynamically via GetKeysforeach(var prop_name in entity.GetKeys()){varobj_val= entity[prop_name]??"null";
record.Add(obj_val.ToString());}
System.Diagnostics.Debug.WriteLine($"{entity_type}[{e++}] "+string.Join(", ", record));//or use "Process a KnowledgeGraphRow Value" snippet//ProcessKnowledgeGraphRowValue(entity);}}}//WaitForRowsAsync}//SubmitSearch
Convert an Open Cypher Query Result to a Selection
QueuedTask.Run(async()=>{//Given an open-cypher qry against an entity or relationship typevarqry=@"MATCH (p:PhoneNumber) RETURN p LIMIT 10";//create a KG query filtervarkg_qry_filter=new KnowledgeGraphQueryFilter(){QueryText=qry};//save a list of the idsvaroids=newList<long>();using(varkgRowCursor= kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(await kgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow= kgRowCursor.Current){varcell_phone= graphRow[0]as KnowledgeGraphEntityValue;//note: some user-managed graphs do not have objectids oids.Add(cell_phone.GetObjectID());}}}}//create a query filter using the oidsif(oids.Count >0){//select them on the layervarqf=new QueryFilter(){ObjectIDs=oids//apply the oids to the ObjectIds property};//select the child feature layer or standalone table representing//the given entity or relate type whose records are to be selectedvarphone_number_fl= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(l => l.Name =="PhoneNumber");//perform the selection phone_number_fl.Select(qf);}});
Use Bind Parameters with an Open Cypher Query
QueuedTask.Run(async()=>{//assume we have, in this case, a list of ids (perhaps retrieved//via a selection, hardcoded (like here), etc.varoids=newList<long>(){3,4,7,8,9,11,12,14,15,19,21,25,29,31,32,36,37,51,53,54,55,56,59,63,75,78,80,84,86,88,96,97,98,101,103,106};//In the query, we refer to the "bind parameter" with the//"$" and a variable name - '$object_ids' in this examplevarqry=@"MATCH (p:PhoneNumber) "+@" WHERE p.objectid IN $object_ids "+@"RETURN p";//we provide the values to be substituted for the variable via the//KnowledgeGraphQueryFilter BindParameter property...varkg_qry_filter=new KnowledgeGraphQueryFilter(){QueryText=qry};//the bind parameter added to the query filter must refer to//the variable name used in the query string (without the "$")//Note://Collections must be converted to a KnowledgeGraphArrayValue before//being assigned to a BindParametervarkg_oid_array=new KnowledgeGraphArrayValue(); kg_oid_array.AddRange(oids); oids.Clear(); kg_qry_filter.BindParameters["object_ids"]=kg_oid_array;//submit the queryusing(varkgRowCursor= kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(await kgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow= kgRowCursor.Current){varcell_phone= graphRow[0]as KnowledgeGraphEntityValue;varoid= cell_phone.GetObjectID();varname=(string)cell_phone["FULL_NAME"];varph_number=(string)cell_phone["PHONE_NUMBER"]; System.Diagnostics.Debug.WriteLine($"[{oid}] {name}, {ph_number}");}}}}});
Use Bind Parameters with an Open Cypher Query2
QueuedTask.Run(async ()=>{//assume we have, in this case, a list of ids (perhaps retrieved//via a selection, hardcoded (like here), etc.varoids=newList<long>(){3,4,7,8,9,11,12,14,15,19,21,25,29,31,32,36,37,51,53,54,55,56,59,63,75,78,80,84,86,88,96,97,98,101,103,106};//In the query, we refer to the "bind parameter" with the//"$" and a variable name - '$object_ids' and '$sel_geom'//in this examplevarqry=@"MATCH (p:PhoneNumber) "+@"WHERE p.objectid IN $object_ids AND "+@"esri.graph.ST_Intersects($sel_geom, p.shape) "+@"RETURN p";//create a KG query filtervarkg_qry_filter=new KnowledgeGraphQueryFilter(){QueryText=qry};//the bind parameter added to the query filter must refer to//the variable name used in the query string (without the "$")//Note://Collections must be converted to a KnowledgeGraphArrayValue before//being assigned to a BindParametervarkg_oid_array=new KnowledgeGraphArrayValue();
kg_oid_array.AddRange(oids);
kg_qry_filter.BindParameters["object_ids"]=kg_oid_array;
kg_qry_filter.BindParameters["sel_geom"]=poly;
oids.Clear();//submit the queryusing(varkgRowCursor= kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(await kgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow= kgRowCursor.Current){
#region Process Row
varcell_phone= graphRow[0]as KnowledgeGraphEntityValue;varoid= cell_phone.GetObjectID();varname=(string)cell_phone["FULL_NAME"];varph_number=(string)cell_phone["PHONE_NUMBER"];
System.Diagnostics.Debug.WriteLine($"[{oid}] {name}, {ph_number}");
Call WaitForRowsAsync With Cancellation
//On the QueuedTask...//and assuming you have established a connection to a knowledge graph//...//submit query or search to return a KnowledgeGraphCursor//using (var kg_rc = kg.SubmitQuery(kg_qf)) {//using (var kg_rc = kg.SubmitSearch(kg_sf)) {//...//wait for rows to be returned from the server//"auto-cancel" after 20 secondsvarcancel=new CancellationTokenSource(new TimeSpan(0,0,20));//catch TaskCanceledExceptiontry{while(await kg_rc.WaitForRowsAsync(cancel.Token)){//check for row eventswhile(kg_rc.MoveNext()){using(vargraph_row= kg_rc.Current){//Graph row is an array, process all returned values...varval_count=(int)graph_row.GetCount();for(inti=0;i<val_count;i++){varretval= graph_row[i];//Process row value (note: recursive)//See "Process a KnowledgeGraphRow Value" snippet
ProcessKnowledgeGraphRowValue(retval);}}}}}//Timeout expiredcatch(TaskCanceledExceptiontce){//Handle cancellation as needed}
cancel.Dispose();
Process a KnowledgeGraphRow Value
//Base class for entities and relationships//(including documents and provenance)publicvoidProcessGraphNamedObjectValue(KnowledgeGraphNamedObjectValuekg_named_obj_val){if(kg_named_obj_val is KnowledgeGraphEntityValue kg_entity){varlabel= kg_entity.GetLabel();//TODO - use label}elseif(kg_named_obj_val is KnowledgeGraphRelationshipValue kg_rel){varhas_entity_ids= kg_rel.GetHasRelatedEntityIDs();if(kg_rel.GetHasRelatedEntityIDs()){varorigin_id= kg_rel.GetOriginID();vardest_id= kg_rel.GetDestinationID();//TODO - use ids}}varid= kg_named_obj_val.GetID();varoid= kg_named_obj_val.GetObjectID();//Note: Typename corresponds to the name of the feature class or table//in the relational gdb model -and- to the name of the KnowledgeGraphNamedObjectType//in the knowledge graph data modelvartype_name= kg_named_obj_val.GetTypeName();//TODO use id, object id, etc.}//Object values include entities, relationships, and anonymous objectspublicvoidProcessGraphObjectValue(KnowledgeGraphObjectValuekg_obj_val){switch(kg_obj_val){case KnowledgeGraphEntityValue kg_entity:
ProcessGraphNamedObjectValue(kg_entity);break;case KnowledgeGraphRelationshipValue kg_rel:
ProcessGraphNamedObjectValue(kg_rel);break;default://Anonymous objectsbreak;}//graph object values have a set of properties (equivalent//to a collection of key/value pairs)varkeys= kg_obj_val.GetKeys();foreach(var key in keys)
ProcessKnowledgeGraphRowValue(kg_obj_val[key]);//Recurse}//Process a KnowledgeGraphValue from a query or searchpublicvoidProcessGraphValue(KnowledgeGraphValuekg_val){switch(kg_val){case KnowledgeGraphPrimitiveValue kg_prim://KnowledgeGraphPrimitiveValue not currently used in//query and search
ProcessKnowledgeGraphRowValue(kg_prim.GetValue());//Recursereturn;case KnowledgeGraphArrayValue kg_array:varcount= kg_array.GetSize();//Recursively process each value in the arrayfor(ulongi=0;i<count;i++)
ProcessKnowledgeGraphRowValue(kg_array[i]);//Recursereturn;case KnowledgeGraphPathValue kg_path://Entitiesvarentity_count= kg_path.GetEntityCount();//Recursively process each entity value in the pathfor(ulongi=0;i<entity_count;i++)
ProcessGraphObjectValue(kg_path.GetEntity(i));//Recurse//Recursively process each relationship value in the pathvarrelate_count= kg_path.GetRelationshipCount();for(ulongi=0;i<relate_count;i++)
ProcessGraphObjectValue(kg_path.GetRelationship(i));//Recursereturn;case KnowledgeGraphObjectValue kg_object:
ProcessGraphObjectValue(kg_object);//Recursereturn;default:vartype_string= kg_val.GetType().ToString();
System.Diagnostics.Debug.WriteLine($"Unknown: '{type_string}'");return;}}//Process each value from the KnowledgeGraphRow arraypublicvoidProcessKnowledgeGraphRowValue(objectvalue){switch(value){//Graph value?case KnowledgeGraphValue kg_val:varkg_type= kg_val.KnowledgeGraphValueType.ToString();
System.Diagnostics.Debug.WriteLine($"KnowledgeGraphValue: '{kg_type}'");
ProcessGraphValue(kg_val);//Recursereturn;//Primitive types...add additional logic as neededcase System.DBNull dbn:
System.Diagnostics.Debug.WriteLine("DBNull.Value");return;casestring str:
System.Diagnostics.Debug.WriteLine($"'{str}' (string)");return;caselong l_val:
System.Diagnostics.Debug.WriteLine($"{l_val} (long)");return;caseint i_val:
System.Diagnostics.Debug.WriteLine($"{i_val} (int)");return;caseshort s_val:
System.Diagnostics.Debug.WriteLine($"{s_val} (short)");return;casedouble d_val:
System.Diagnostics.Debug.WriteLine($"{d_val} (double)");return;casefloat f_val:
System.Diagnostics.Debug.WriteLine($"{f_val} (float)");return;case DateTime dt_val:
System.Diagnostics.Debug.WriteLine($"{dt_val} (DateTime)");return;case DateOnly dt_only_val:
System.Diagnostics.Debug.WriteLine($"{dt_only_val} (DateOnly)");return;case TimeOnly tm_only_val:
System.Diagnostics.Debug.WriteLine($"{tm_only_val} (TimeOnly)");return;case DateTimeOffset dt_tm_offset_val:
System.Diagnostics.Debug.WriteLine($"{dt_tm_offset_val} (DateTimeOffset)");return;case System.Guid guid_val:varguid_string= guid_val.ToString("B");
System.Diagnostics.Debug.WriteLine($"'{guid_string}' (Guid)");return;case Geometry geom_val:vargeom_type= geom_val.GeometryType.ToString();varis_empty= geom_val.IsEmpty;varwkid= geom_val.SpatialReference?.Wkid ??0;
System.Diagnostics.Debug.WriteLine($"geometry: {geom_type}, empty: {is_empty}, sr_wkid {wkid} (shape)");return;default://Blob? Others?vartype_str= value.GetType().ToString();
System.Diagnostics.Debug.WriteLine($"Primitive: {type_str}");return;}}// ...submit query or search//using (var kg_rc = kg.SubmitQuery(kg_qf)) {//using (var kg_rc = kg.SubmitSearch(kg_sf)) {// ...wait for rows ...// while (await kg_rc.WaitForRowsAsync()) {// ...rows have been retrieved// while (kg_rc.MoveNext()) {// ...get the current KnowledgeGraphRow// using (var graph_row = kg_rc.Current) {// var val_count = (int)graph_row.GetCount();// for (int i = 0; i<val_count; i++)// ProcessKnowledgeGraphRowValue(graph_row[i]);
Link Charts
Find link chart project items
// find all the link chart project itemsvarlinkChartItems= Project.Current.GetItems<MapProjectItem>().Where(pi => pi.MapType == MapType.LinkChart);// find a link chart project item by namevarlinkChartItem= Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi => pi.Name =="Acme Link Chart");
Find link chart map by name
varprojectItem= Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi => pi.Name =="Acme Link Chart");varlinkChartMap= projectItem?.GetMap();
Does Active MapView contain a link chart map
varmv= MapView.Active;// check the viewvarisLinkChartView= mv.IsLinkChartView;// or alternatively get the map and check thatvarmap= MapView.Active.Map;// check the MapType to determine if it's a link chart mapvarisLinkChart= map.MapType == MapType.LinkChart;// or you could use the following// var isLinkChart = map.IsLinkChart;
varmv= MapView.Active;// a MapView can encapsulate a link chart IF it's map// is of type MapType.LinkChartvarmap= mv.Map;varisLinkChart= map.MapType == MapType.LinkChart;// or use the following// var isLinkChart = map.IsLinkChart;
QueuedTask.Run(()=>{if(isLinkChart){// get the layout algorithmvarlayoutAlgorithm= mv.GetLinkChartLayout();// toggle the valueif(layoutAlgorithm== KnowledgeLinkChartLayoutAlgorithm.Geographic_Organic_Standard)layoutAlgorithm= KnowledgeLinkChartLayoutAlgorithm.Organic_Standard;elselayoutAlgorithm= KnowledgeLinkChartLayoutAlgorithm.Geographic_Organic_Standard;// set it mv.SetLinkChartLayoutAsync(layoutAlgorithm);// OR set it and force a redraw / update// await mv.SetLinkChartLayoutAsync(layoutAlgorithm, true);}});
Create and Append to Link Charts
Create a Link Chart Containing All Records for a KG
QueuedTask.Run(()=>{//Create the link chart and show it//build the IDSet using KnowledgeGraphFilterType.AllNamedObjectsvaridSet= KnowledgeGraphLayerIDSet.FromKnowledgeGraph( kg, KnowledgeGraphFilterType.AllNamedObjects);varlinkChart= MapFactory.Instance.CreateLinkChart("KG Link Chart", kg, idSet); FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);});
Create a Link Chart With an Empty KG Layer
QueuedTask.Run(()=>{//Create the link chart with a -null- id set//This will create a KG Layer with empty sub-layers//(Note: you cannot create an empty KG layer on a map - only on a link chart)varlinkChart= MapFactory.Instance.CreateLinkChart("KG Link Chart", kg,null); FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);});
Create a link chart with all the entities of the Knowledge Graph
//use the results of a query to create an idset. Create the link chart//containing just records corresponding to the query resultsvarqry=@"MATCH (p1:PhoneNumber)-[r1:MADE_CALL|RECEIVED_CALL]->(c1:PhoneCall)<-"+@"[r2:MADE_CALL|RECEIVED_CALL]-(p2:PhoneNumber)-[r3:MADE_CALL|RECEIVED_CALL]"+@"->(c2:PhoneCall)<-[r4:MADE_CALL|RECEIVED_CALL]-(p3:PhoneNumber) "+@"WHERE p1.FULL_NAME = ""Robert Johnson"" AND "+@"p3.FULL_NAME= ""Dan Brown"" AND "+@"p1.globalid <> p2.globalid AND "+@"p2.globalid <> p3.globalid "+@"RETURN p1, r1, c1, r2, p2, r3, c2, r4, p3";vardict=newDictionary<string,List<long>>();
QueuedTask.Run(async()=>{using(varkg= kg_layer.GetDatastore()){vargraphQuery=new KnowledgeGraphQueryFilter(){QueryText=qry};using(varkgRowCursor= kg.SubmitQuery(graphQuery)){while(await kgRowCursor.WaitForRowsAsync()){while(kgRowCursor.MoveNext()){using(vargraphRow= kgRowCursor.Current){// process the rowvarcnt_val=(int)graphRow.GetCount();for(intv=0;v<cnt_val;v++){varobj_val= graphRow[v]as KnowledgeGraphNamedObjectValue;vartype_name= obj_val.GetTypeName();varoid=(long)obj_val.GetObjectID();if(!dict.ContainsKey(type_name)){ dict[type_name]=newList<long>();}if(!dict[type_name].Contains(oid)) dict[type_name].Add(oid);}}}}}//make an ID Set to create the LinkChartvaridSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict);//Create the link chart and show itvarlinkChart= MapFactory.Instance.CreateLinkChart("KG With ID Set", kg, idSet); FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);}});
Create a link chart based on a template link chart
// note that the template link chart MUST use the same KG serverstringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";
QueuedTask.Run(()=>{// find the existing link chart by namevarprojectItem= Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi => pi.Name =="Acme Link Chart");varlinkChartMap= projectItem?.GetMap();if(linkChartMap==null)return;//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));try{//Open a connectionusing(varkg=new KnowledgeGraph(kg_props)){//Add all entities to the link chartvaridSet= KnowledgeGraphLayerIDSet.FromKnowledgeGraph( kg, KnowledgeGraphFilterType.AllEntities);//Create the new link chart and show itvarnewLinkChart= MapFactory.Instance.CreateLinkChart("KG from Template", kg, idSet, linkChartMap.URI); FrameworkApplication.Panes.CreateMapPaneAsync(newLinkChart);}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}});
Checking KnowledgeGraphLayerException
// running on QueuedTaskvardict=newDictionary<string,List<long>>();
dict.Add("person",newList<long>());//Empty list means all records
dict.Add("made_call",null);//null list means all records// or specific records - however the ids are obtained
dict.Add("phone_call",newList<long>(){1,5,18,36,78});// make the id setvaridSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict);try{//Create the link chart and show itvarlinkChart= MapFactory.Instance.CreateLinkChart("KG With ID Set", kg, idSet);
FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);}catch(KnowledgeGraphLayerExceptione){// get the invalid named types// remember that the named types are case-sensitivevarinvalidNamedTypes= e.InvalidNamedTypes;// do something with the invalid named types // for example - log or return to caller to show message to user}
Append to Link Chart
//We create an id set to contain the records to be appendedvardict=newDictionary<string,List<long>>();
dict["Suspects"]=newList<long>();//In this case, via results from a query...varqry2="MATCH (s:Suspects) RETURN s";
QueuedTask.Run(async()=>{using(varkg= kg_layer.GetDatastore()){vargraphQuery=new KnowledgeGraphQueryFilter(){QueryText=qry2};using(varkgRowCursor= kg.SubmitQuery(graphQuery)){while(await kgRowCursor.WaitForRowsAsync()){while(kgRowCursor.MoveNext()){using(vargraphRow= kgRowCursor.Current){varobj_val= graphRow[0]as KnowledgeGraphNamedObjectValue;varoid=(long)obj_val.GetObjectID(); dict["Suspects"].Add(oid);}}}}//make an ID Set to append to the LinkChartvaridSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, dict);//Get the relevant link chart to which records will be//appended...in this case, from an open map pane in the//Pro application...varmapPanes= FrameworkApplication.Panes.OfType<IMapPane>().ToList();varmapPane= mapPanes.First(mp => mp.MapView.IsLinkChartView && mp.MapView.Map.Name =="Acme Link Chart");varlinkChartMap= mapPane.MapView.Map;//or get the link chart from an item in the catalog...etc.,etc.//var projectItem = Project.Current.GetItems<MapProjectItem>()// .FirstOrDefault(pi => pi.Name == "Acme Link Chart");//var linkChartMap = projectItem?.GetMap();//Call AppendToLinkChart with the id setif(linkChartMap.CanAppendToLinkChart(idSet)) linkChartMap.AppendToLinkChart(idSet);}});
ID Sets
Get the ID Set of a KG layer
QueuedTask.Run(()=>{varidSet= kgLayer.GetIDSet();// is the set empty?varisEmpty= idSet.IsEmpty;// get the count of named object typesvarcountNamedObjects= idSet.NamedObjectTypeCount;// does it contain the entity "Species";varcontains= idSet.Contains("Species");// get the idSet as a dictionary of namedObjectType and oidsvaroidDict= idSet.ToOIDDictionary();varspeciesOIDs= oidDict["Species"];// alternatively get the idSet as a dictionary of // namedObjectTypes and uuidsvaruuidDict= idSet.ToUIDDictionary();varspeciesUuids= uuidDict["Species"];});
Create an ID set from a SelectionSet
QueuedTask.Run(()=>{// get the selection setvarsSet= map.GetSelection();// translate to an KnowledgeGraphLayerIDSet// if the selectionset does not contain any KG entity or relationship records// then idSet will be null varidSet= KnowledgeGraphLayerIDSet.FromSelectionSet(sSet);if(idSet==null)return;// you can use the idSet to create a new linkChart// (using MapFactory.Instance.CreateLinkChart)});
await QueuedTask.Run(()=>{MapMemberIDSetrootNodes= MapView.Active.GetRootNodes();varrootNodeDict= rootNodes.ToDictionary();// rootNodeDict is a Dictionary<MapMember, List<long>>// access a particular mapMember in the Dictionaryif(rootNodeDict.ContainsKey(mapMember)){varoids= rootNodeDict[mapMember];}// OR iterate through the dictionaryforeach(var(mm, oids)in rootNodeDict){// do something}});
await QueuedTask.Run(()=>{varmapSel= MapView.Active.SelectAllRootNodes();// this is the same as MapMemberIDSetrootNodes= MapView.Active.GetRootNodes();SelectionSetselSet= SelectionSet.FromMapMemberIDSet(rootNodes); MapView.Active.Map.SetSelection(selSet);});
await QueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=new EditOperation(){Name="Create a new organization",SelectNewFeatures=true};//Use datasets or feature layer(s) or standalone table(s)//Get a reference to the KnowledgeGraph//var kg = ... ; //Open the feature class or Table to be editedvarorg_fc= kg.OpenDataset<FeatureClass>("Organization");//Alternatively, use the feature layer for 'Organization' if your context is a map//Get the parent KnowledgeGraphLayervarkg_layer= mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//From the KG Layer get the relevant child feature layervarorg_fl= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer => child_layer.Name =="Organization");//Define attributesvarattribs=newDictionary<string,object>(); attribs["Name"]="Acme Ltd."; attribs["Description"]="Specializes in household items"; attribs["SHAPE"]=org_location;//Add it to the operation via the dataset... edit_op.Create(org_fc, attribs);//or use the feature layer/stand alone table if preferred and available//edit_op.Create(org_fl, attribs);if(edit_op.Execute()){//TODO: Operation succeeded}});
Create a new Relationship from Existing Entities 1
varcreate_rel=await QueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_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...varorg_fc= kg.OpenDataset<FeatureClass>("Organization");varperson_tbl= kg.OpenDataset<Table>("Person");//Get the relationship dataset//We can use either a table or standalone tablevaremp_tbl= kg.OpenDataset<Table>("HasEmployee");//we need the names of the origin and destination relationship propertiesvarkg_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 relationshipvarattribs=newDictionary<string,object>();using(varrc= org_fc.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding... attribs[kg_prop_info.OriginIDPropertyName]= rc.Current.GetGlobalID();}using(varrc= 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 createreturn edit_op.Execute();});
Create a new Relationship from Existing Entities 2
varcreate_rel2=await QueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_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...varorg_fc= kg.OpenDataset<FeatureClass>("Organization");varperson_tbl= kg.OpenDataset<Table>("Person");//Get the relationship dataset//We can use either a table or standalone tablevaremp_tbl= kg.OpenDataset<Table>("HasEmployee");// get the origin, destination recordsGuidguidOrigin= Guid.Empty;GuidguidDestination= Guid.Empty;using(varrc= org_fc.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidOrigin= rc.Current.GetGlobalID();}using(varrc= person_tbl.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidDestination= rc.Current.GetGlobalID();}//Add any extra attribute information for the relation as neededvarattribs=newDictionary<string,object>(); attribs["StartDate"]=new DateTimeOffset(DateTime.Now);varrd=new KnowledgeGraphRelationshipDescription(guidOrigin, guidDestination, attribs);//Add a create for the relationship to the operation edit_op.Create(emp_tbl, rd);//Do the createreturn edit_op.Execute();});
Create a new Relationship and New Entities 1
varcreate_rel1=await QueuedTask.Run(()=>{//This example uses a chained edit operationvaredit_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)varorg_fc= kg.OpenDataset<FeatureClass>("Organization");varperson_tbl= kg.OpenDataset<Table>("Person");//Relationship tablevaremp_tbl= kg.OpenDataset<Table>("HasEmployee");varattribs=newDictionary<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 rowtokenvarrowtoken= 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 operationvarrowtoken2= edit_op.Create(person_tbl, attribs); attribs.Clear();//At this point we must execute the create of the entitiesif(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- transactionvaredit_op_rel= edit_op.CreateChainedOperation();//we need the names of the origin and destination relation propertiesvarkg_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();}returnfalse;//Create of entities failed});
Create a new Relationship and New Entities 2
varcreateRel=await QueuedTask.Run(()=>{//This example uses a KnowledgeGraphRelationshipDescriptionvaredit_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/tablesvarkg_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)varorg_fl= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer => child_layer.Name =="Organization");varperson_stbl= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="Person");varrel_stbl= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="HasEmployee");varattribs=newDictionary<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 rowtokenvarrowtoken_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 operationvarrowtoken_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 relatedvarsrc_row_handle=new RowHandle(rowtoken_org);vardest_row_handle=new RowHandle(rowtoken_person);//Add any extra attribute information for the relation as needed attribs["StartDate"]=new DateTimeOffset(DateTime.Now);varrel_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 relationshipreturn edit_op.Execute();});
Create a Provenance Record
await QueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=new EditOperation(){Name="Create a new provenance record",SelectNewFeatures=true};//lets get the provenance table (provenance is not added to the//map TOC)varprovenance_tbl= kg.OpenDataset<Table>("Provenance");if(provenance_tbl==null)return;//we will add a row to the provenance for person entityvarperson_tbl= kg.OpenDataset<Table>("Person");//Arbitrarily retrieve the first "person" rowvarinstance_id= Guid.Empty;using(varrc= 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 ProvenancePropertyInfovarkg_prop_info= kg.GetPropertyNameInfo();varattribs=newDictionary<string,object>();varppi= 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 Document Record
internalstaticstringGetDocumentTypeName(KnowledgeGraphDataModelkg_dm){varentity_types= kg_dm.GetEntityTypes();foreach(var entity_type in entity_types){varrole= entity_type.Value.GetRole();if(role== KnowledgeGraphNamedObjectTypeRole.Document)return entity_type.Value.GetName();}return"";}internalstaticstringGetHasDocumentTypeName(KnowledgeGraphDataModelkg_dm){varrel_types= kg_dm.GetRelationshipTypes();foreach(var rel_type in rel_types){varrole= rel_type.Value.GetRole();if(role== KnowledgeGraphNamedObjectTypeRole.Document)return rel_type.Value.GetName();}return"";}internalasyncvoidAddDocumentRecord(){await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){varedit_op=new EditOperation(){Name="Create Document Example",SelectNewFeatures=true};vardoc_entity_name= GetDocumentTypeName(kg.GetDataModel());if(string.IsNullOrEmpty(doc_entity_name))returnfalse;varhasdoc_rel_name= GetHasDocumentTypeName(kg.GetDataModel());if(string.IsNullOrEmpty(hasdoc_rel_name))returnfalse;//Document can also be FeatureClassvardoc_tbl= kg.OpenDataset<Table>(doc_entity_name);vardoc_rel_tbl= kg.OpenDataset<Table>(hasdoc_rel_name);//This is the document to be added...file, image, resource, etc.varurl=@"E:\Data\Temp\HelloWorld.txt";vartext= System.IO.File.ReadAllText(url);//Set document propertiesvarattribs=newDictionary<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...varorg_fc= kg.OpenDataset<FeatureClass>("Organization");varqf=new QueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};varorigin_org_id= Guid.Empty;using(varrc= org_fc.Search(qf)){if(!rc.MoveNext())returnfalse;origin_org_id= rc.Current.GetGlobalID();//For the relate}//Create the document row/featurevarrowtoken= 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 propertiesvarkg_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- transactionvaredit_op_rel= edit_op.CreateChainedOperation(); edit_op_rel.Create(doc_rel_tbl, attribs);return edit_op_rel.Execute();}}returnfalse;});}
Modify an Entity and Relationship record
await QueuedTask.Run(()=>{varedit_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/tablesvarkg_layer= mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Entityvarorg_fl= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer => child_layer.Name =="Organization");//and/or Relationshipvarrel_stbl= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="HasEmployee");//Get the entity feature to modifylongorg_oid=-1;varorg_gid= Guid.Empty;varqf=new QueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};using(varrc= 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 modifyvarattribs=newDictionary<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 propertyvarkg_prop_info= kg.GetPropertyNameInfo();varsql=$"{kg_prop_info.OriginIDPropertyName} = ";sql+="'"+ org_gid.ToString("B").ToUpper()+"'";qf=new QueryFilter(){WhereClause=sql,SubFields="*"};longrel_oid=-1;using(varrc= 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}});
Delete an Entity record
await QueuedTask.Run(()=>{varedit_op=new EditOperation(){Name="Delete an Entity record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer= mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Entityvarorg_fl= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer => child_layer.Name =="Organization");//Get the entity feature(s) to deletelongorg_oid=-1;varqf=new QueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};using(varrc= org_fl.Search(qf)){if(!rc.MoveNext())return;//nothing to deleteorg_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(()=>{varedit_op=new EditOperation(){Name="Delete a Relationship record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer= mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Relationshipvarrel_stbl= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="HasEmployee");//Get the relation row to deletelongrel_oid=-1;using(varrc= rel_stbl.Search()){if(!rc.MoveNext())return;//arbitrarily, in this example, get the first rowrel_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(()=>{varedit_op=new EditOperation(){Name="Delete a Relationship record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer= mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//entitiesvarentityOrg= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="Organization");varentityPerson= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="Person");//Relationshipvarrel_stbl= kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer => child_layer.Name =="HasEmployee");// get the origin, destination recordsGuidguidOrigin= Guid.Empty;GuidguidDestination= Guid.Empty;using(varrc= entityOrg.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidOrigin= rc.Current.GetGlobalID();}using(varrc= entityPerson.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidDestination= rc.Current.GetGlobalID();}varrd=new KnowledgeGraphRelationshipDescription(guidOrigin, guidDestination); edit_op.Delete(rel_stbl, rd); edit_op.Execute();//Do the delete});
Schema Edits
Create Entity and Relationship Types with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";varrelate_name="WhoCalledWho";//Entity Fieldsvardescs1=newList<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 Fieldsvardescs2=newList<KnowledgeGraphPropertyDescription>(); descs2.Add(new KnowledgeGraphPropertyDescription("Foo", FieldType.String)); descs2.Add(new KnowledgeGraphPropertyDescription("Bar", FieldType.String));varincludeShape=true;//change to false to omit the shape columnvarhasZ=false;varhasM=false;KnowledgeGraphEntityTypeDescriptionentityDesc=null;KnowledgeGraphRelationshipTypeDescriptionrelateDesc=null;if(includeShape){varsr= kg.GetSpatialReference();varshp_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 buildertry{SchemaBuildersb=new(kg); sb.Create(entityDesc); sb.Create(relateDesc);//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Entity/Relate Create error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Entity and Relationship Types with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";varrelate_name="WhoCalledWho";varentityDesc=new KnowledgeGraphEntityTypeDescription(entity_name);varrelateDesc=new KnowledgeGraphRelationshipTypeDescription(relate_name);//Run the schema buildertry{SchemaBuildersb=new(kg); sb.Delete(entityDesc); sb.Delete(relateDesc);//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Entity/Relate Delete error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Modify Entity and Relationship Type Schemas with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";varrelate_name="WhoCalledWho";varkvp_entity= kg.GetDataModel().GetEntityTypes().First(r => r.Key ==entity_name);varkvp_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 listvarentity_props= kvp_entity.Value.GetProperties().Reverse().Skip(1).Reverse();varprop_descs=newList<KnowledgeGraphPropertyDescription>();foreach(var prop in entity_props){if(prop.FieldType == FieldType.Geometry){continue;//skip shape}varprop_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" listShapeDescriptionshape_desc=null;if(kvp_entity.Value.GetIsSpatial()){vargeom_def= kvp_entity.Value.GetShapeDefinition();varshape_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 nullvarentityDesc=new KnowledgeGraphEntityTypeDescription( entity_name, prop_descs, shape_desc);//Add the entity type description to the schema builder using 'Modify'SchemaBuildersb=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...varrel_props= kvp_relate.Value.GetProperties().Reverse().Skip(1).Reverse();varrel_prop_descs=newList<KnowledgeGraphPropertyDescription>();foreach(var prop in rel_props){if(prop.FieldType == FieldType.Geometry){continue;//skip shape}varprop_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" listShapeDescriptionshape_desc_rel=null;if(kvp_relate.Value.GetIsSpatial()){vargeom_def= kvp_relate.Value.GetShapeDefinition();varshape_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 nullvarrelDesc=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 buildertry{//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Entity/Relate Modify error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Create Attribute Indexes on KG Schemas with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";//indexes are managed on the GDB objects...varentity_table_def= kg.GetDefinition<TableDefinition>(entity_name);varentity_table_desc=new TableDescription(entity_table_def);varentity_table_flds= entity_table_def.GetFields();AttributeIndexDescriptionattr_index1=null;AttributeIndexDescriptionattr_index2=null;foreach(var fld in entity_table_flds){//index the first string fieldif(fld.FieldType == FieldType.String &&attr_index1==null){if(fld.Name =="ESRI__ID")//special casecontinue;//Index _must_ be ascending for KGattr_index1=new AttributeIndexDescription("Index1", entity_table_desc,newList<string>{ fld.Name }){IsAscending=true};}//index the first numeric field (if there is one)if((fld.FieldType == FieldType.BigInteger || fld.FieldType == FieldType.Integer || fld.FieldType == FieldType.Single || fld.FieldType == FieldType.SmallInteger || fld.FieldType == FieldType.Double)&&attr_index2==null){attr_index2=new AttributeIndexDescription("Index2", entity_table_desc,newList<string>{ fld.Name }){IsAscending=true,IsUnique=true//optional - unique if all values are to be unique in the index};}if(attr_index1!=null&&attr_index2!=null)break;}if(attr_index1==null&&attr_index2==null)return;//nothing to index//Run the schema buildertry{SchemaBuildersb=new(kg);if(attr_index1!=null) sb.Create(attr_index1);if(attr_index2!=null) sb.Create(attr_index2);if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Create index error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Attribute Indexes on KG Schemas with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";//indexes are managed on the GDB objects...varentity_table_def= kg.GetDefinition<TableDefinition>(entity_name);varentity_table_desc=new TableDescription(entity_table_def);varindexes= entity_table_def.GetIndexes();foreach(var idx in indexes){ System.Diagnostics.Debug.WriteLine($"Index {idx.GetName()}");}varidx1= indexes.FirstOrDefault(idx => idx.GetName().ToLower()=="Index1".ToLower());varidx2= indexes.FirstOrDefault(idx => idx.GetName().ToLower()=="Index2".ToLower());if(idx1==null&&idx2==null)return;//Run the schema buildertry{SchemaBuildersb=new(kg);if(idx1!=null){varidx_attr=new AttributeIndexDescription(idx1, entity_table_desc); sb.Delete(idx_attr);}if(idx2!=null){varidx_attr=new AttributeIndexDescription(idx2, entity_table_desc); sb.Delete(idx_attr);}if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Delete index error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Create Domain and Field Definition on KG Schemas with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;varentity_name="Fruit";//Domains are managed on the GDB objects...varfruit_fc= kg.OpenDataset<FeatureClass>(entity_name);varfruit_fc_def= fruit_fc.GetDefinition();varfieldFruitTypes= fruit_fc_def.GetFields().FirstOrDefault(f => f.Name =="FruitTypes");varfieldShelfLife= fruit_fc_def.GetFields().FirstOrDefault(f => f.Name =="ShelfLife");//Create a coded value domain and add it to a new fieldvarfruit_cvd_desc=new CodedValueDomainDescription("FruitTypes", FieldType.String,newSortedList<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 alsovarshelf_life_rd_desc=new RangeDomainDescription("ShelfLife", FieldType.Integer,0,14);varsb=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 domainvarfruit_types_fld=new ArcGIS.Core.Data.DDL.FieldDescription("FruitTypes", FieldType.String); fruit_types_fld.SetDomainDescription(fruit_cvd_desc);//ShelfLife will use the range domainvarshelf_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.varfruit_fc_desc=new FeatureClassDescription(fruit_fc_def);varmodified_fld_descs=newList<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 domainsvarupdated_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 buildertry{if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Create domains error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Domain on KG Schemas with SchemaBuilder
await QueuedTask.Run(()=>{using(varkg= GetKnowledgeGraph()){if(kg==null)return;//Get all the domains in the KGvardomains= kg.GetDomains();varsb=new SchemaBuilder(kg);foreach(var domain in domains){//skip the special provenance domainvarname= domain.GetName();if(string.Compare(name,"esri__provenanceSourceType",true)==0)continue;//skip this one//Delete all other domainsif(domain is RangeDomain rd) sb.Delete(new RangeDomainDescription(rd));elseif(domain is CodedValueDomain cvd) sb.Delete(new CodedValueDomainDescription(cvd));}try{//note: will throw an InvalidOperationException if there are no operations//to run. Will also delete associated fields dependent on deleted domain(s)if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",", sb.ErrorMessages.ToArray()); System.Diagnostics.Debug.WriteLine($"Delete domains error: {err_msg}");}}catch(Exceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}}});