stringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));try{//Open a connectionusing(varkg=newKnowledgeGraph(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()asKnowledgeGraph;//TODO use KnowledgeGraph}else{//try standalone tablevarstbl=kgLayer?.GetStandaloneTablesAsFlattenedList()?.FirstOrDefault();if(stbl!=null){using(vartbl=stbl.GetTable())kg=tbl.GetDatastore()asKnowledgeGraph;//TODO use KnowledgeGraph}}});
Retrieving GDB FeatureClasses and Definitions
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(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(varfc_definfc_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=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(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(vartbl_defintbl_defs){vartbl_name=tbl_def.GetName();using(varfc=kg.OpenDataset<Table>(tbl_name)){//TODO - use the table}}}});
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(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=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(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=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(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_infoisKnowledgeGraphNativeIdentifierkg_ni){System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphNativeIdentifier");}elseif(kg_id_infoisKnowledgeGraphUniformIdentifierkg_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=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(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(varkvpindict_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(varentity_typeinentity_types){if(entity_type.Value.GetRole()==KnowledgeGraphNamedObjectTypeRole.Provenance)returnentity_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();returnpropInfo.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=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){vardict_types=kg_dm.GetEntityTypes();foreach(varkvpindict_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(varentity_typeinentity_types){varrole=entity_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnentity_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;returnentity.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();returnprops.Any(prop =>prop.FieldType==FieldType.Geometry);}
Get KnowledgeGraph Relationship Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){vardict_types=kg_dm.GetRelationshipTypes();foreach(varkvpindict_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(varend_pointinend_points){System.Diagnostics.Debug.WriteLine($"Origin: '{end_point.GetOriginEntityTypeName()}', "+$"Destination: '{end_point.GetDestinationEntityTypeName()}'");}}}}});
Get All KnowledgeGraph Graph Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_datamodel=kg.GetDataModel()){varentities=kg_datamodel.GetEntityTypes();varrelationships=kg_datamodel.GetRelationshipTypes();varprovenance=kg_datamodel.GetMetaEntityTypes();varall_graph_types=newList<KnowledgeGraphNamedObjectType>();all_graph_types.AddRange(entities.Values);all_graph_types.AddRange(relationships.Values);all_graph_types.AddRange(provenance.Values);System.Diagnostics.Debug.WriteLine("\r\nGraph Types");intc=0;foreach(vargraph_typeinall_graph_types){vartype_name=graph_type.GetName();varrole=graph_type.GetRole().ToString();//equivalent to://var fields = featClassDef.GetFields().Select(f => f.Name).ToList();//var field_names = string.Join(",", fields);varprops=graph_type.GetProperties().Select(p =>p.Name).ToList();varprop_names=string.Join(",",props);System.Diagnostics.Debug.WriteLine($"[{c++}]: "+$"{type_name}, {role}, {prop_names}");}}}});
KnowledgeGraphLayer Creation with Maps
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=newKnowledgeGraphLayerCreationParams(kg){Name="KG_With_All_Types",IsVisible=false};//Orvarkg_params2=newKnowledgeGraphLayerCreationParams(newUri(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 recordsdict.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=newKnowledgeGraphLayerCreationParams(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=newFeatureLayerCreationParams(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 exceptionLayerFactory.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=newKnowledgeGraphLayerCreationParams(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 recordsdict2.Add("Enity_Or_Relate_Type_Name2",newList<long>());//Empty list means all recordsdict2.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(varchildLayerinchildLayers){if(childLayerisLinkChartFeatureLayerlcFeatureLayer){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(varchildinchidlren){if(childisFeatureLayerfl){// TODO - process the feature layer}elseif(childisStandaloneTablest){// 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 recordsMapFactory.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=newKnowledgeGraphQueryFilter(){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 provenancekg_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(awaitkg_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" snippetProcessKnowledgeGraphRowValue(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=newKnowledgeGraphSearchFilter(){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(awaitkg_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]asKnowledgeGraphEntityValue;varentity_type=entity.GetTypeName();varrecord=newList<string>();//discover keys(aka "fields") dynamically via GetKeysforeach(varprop_nameinentity.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=newKnowledgeGraphQueryFilter(){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(awaitkgRowCursor.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]asKnowledgeGraphEntityValue;//note: some user-managed graphs do not have objectidsoids.Add(cell_phone.GetObjectID());}}}}//create a query filter using the oidsif(oids.Count>0){//select them on the layervarqf=newQueryFilter(){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 selectionphone_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=newKnowledgeGraphQueryFilter(){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=newKnowledgeGraphArrayValue();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(awaitkgRowCursor.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]asKnowledgeGraphEntityValue;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=newKnowledgeGraphQueryFilter(){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=newKnowledgeGraphArrayValue();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(awaitkgRowCursor.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]asKnowledgeGraphEntityValue;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=newCancellationTokenSource(newTimeSpan(0,0,20));//catch TaskCanceledExceptiontry{while(awaitkg_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" snippetProcessKnowledgeGraphRowValue(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_valisKnowledgeGraphEntityValuekg_entity){varlabel=kg_entity.GetLabel();//TODO - use label}elseif(kg_named_obj_valisKnowledgeGraphRelationshipValuekg_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){caseKnowledgeGraphEntityValuekg_entity:ProcessGraphNamedObjectValue(kg_entity);break;caseKnowledgeGraphRelationshipValuekg_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(varkeyinkeys)ProcessKnowledgeGraphRowValue(kg_obj_val[key]);//Recurse}//Process a KnowledgeGraphValue from a query or searchpublicvoidProcessGraphValue(KnowledgeGraphValuekg_val){switch(kg_val){caseKnowledgeGraphPrimitiveValuekg_prim://KnowledgeGraphPrimitiveValue not currently used in//query and search ProcessKnowledgeGraphRowValue(kg_prim.GetValue());//Recursereturn;caseKnowledgeGraphArrayValuekg_array:varcount=kg_array.GetSize();//Recursively process each value in the arrayfor(ulongi=0;i<count;i++)ProcessKnowledgeGraphRowValue(kg_array[i]);//Recursereturn;caseKnowledgeGraphPathValuekg_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;caseKnowledgeGraphObjectValuekg_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?caseKnowledgeGraphValuekg_val:varkg_type=kg_val.KnowledgeGraphValueType.ToString();System.Diagnostics.Debug.WriteLine($"KnowledgeGraphValue: '{kg_type}'");ProcessGraphValue(kg_val);//Recursereturn;//Primitive types...add additional logic as neededcaseSystem.DBNulldbn:System.Diagnostics.Debug.WriteLine("DBNull.Value");return;casestringstr:System.Diagnostics.Debug.WriteLine($"'{str}' (string)");return;caselongl_val:System.Diagnostics.Debug.WriteLine($"{l_val} (long)");return;caseinti_val:System.Diagnostics.Debug.WriteLine($"{i_val} (int)");return;caseshorts_val:System.Diagnostics.Debug.WriteLine($"{s_val} (short)");return;casedoubled_val:System.Diagnostics.Debug.WriteLine($"{d_val} (double)");return;casefloatf_val:System.Diagnostics.Debug.WriteLine($"{f_val} (float)");return;caseDateTimedt_val:System.Diagnostics.Debug.WriteLine($"{dt_val} (DateTime)");return;caseDateOnlydt_only_val:System.Diagnostics.Debug.WriteLine($"{dt_only_val} (DateOnly)");return;caseTimeOnlytm_only_val:System.Diagnostics.Debug.WriteLine($"{tm_only_val} (TimeOnly)");return;caseDateTimeOffsetdt_tm_offset_val:System.Diagnostics.Debug.WriteLine($"{dt_tm_offset_val} (DateTimeOffset)");return;caseSystem.Guidguid_val:varguid_string=guid_val.ToString("B");System.Diagnostics.Debug.WriteLine($"'{guid_string}' (Guid)");return;caseGeometrygeom_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;
Find Link Chart from Map panes
varmapPanes=FrameworkApplication.Panes.OfType<IMapPane>().ToList();varmapPane=mapPanes.FirstOrDefault(
mp =>mp.MapView.IsLinkChartView&&mp.MapView.Map.Name=="Acme Link Chart");varlcMap=mapPane.MapView.Map;
Get and set the link chart layout
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 itmv.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
stringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";QueuedTask.Run(()=>{using(varkg=newKnowledgeGraph(newKnowledgeGraphConnectionProperties(newUri(url)))){varidSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraph(kg,KnowledgeGraphFilterType.AllEntities);varnewLinkChart=MapFactory.Instance.CreateLinkChart("All_Entities link chart",kg,idSet);};});
Create a Link Chart from a query
//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=newKnowledgeGraphQueryFilter(){QueryText=qry};using(varkgRowCursor=kg.SubmitQuery(graphQuery)){while(awaitkgRowCursor.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]asKnowledgeGraphNamedObjectValue;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=newKnowledgeGraphConnectionProperties(newUri(url));try{//Open a connectionusing(varkg=newKnowledgeGraph(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 recordsdict.Add("made_call",null);//null list means all records// or specific records - however the ids are obtaineddict.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=newKnowledgeGraphQueryFilter(){QueryText=qry2};using(varkgRowCursor=kg.SubmitQuery(graphQuery)){while(awaitkgRowCursor.WaitForRowsAsync()){while(kgRowCursor.MoveNext()){using(vargraphRow=kgRowCursor.Current){varobj_val=graphRow[0]asKnowledgeGraphNamedObjectValue;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)});
awaitQueuedTask.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)inrootNodeDict){// do something}});
awaitQueuedTask.Run(()=>{varmapSel=MapView.Active.SelectAllRootNodes();// this is the same as MapMemberIDSetrootNodes=MapView.Active.GetRootNodes();SelectionSetselSet=SelectionSet.FromMapMemberIDSet(rootNodes);MapView.Active.Map.SetSelection(selSet);});
awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){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=awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){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 neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);//Add a create for the relationship to the operationedit_op.Create(emp_tbl,attribs);//Do the createreturnedit_op.Execute();});
Create a new Relationship from Existing Entities 2
varcreate_rel2=awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){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"]=newDateTimeOffset(DateTime.Now);varrd=newKnowledgeGraphRelationshipDescription(guidOrigin,guidDestination,attribs);//Add a create for the relationship to the operationedit_op.Create(emp_tbl,rd);//Do the createreturnedit_op.Execute();});
Create a new Relationship and New Entities 1
varcreate_rel1=awaitQueuedTask.Run(()=>{//This example uses a chained edit operationvaredit_op=newEditOperation(){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 Organizationattribs["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 Personattribs["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 createsattribs[kg_prop_info.OriginIDPropertyName]=rowtoken.GlobalID;attribs[kg_prop_info.DestinationIDPropertyName]=rowtoken2.GlobalID;//Add any extra attribute information for the relation as neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);//Do the create of the relateedit_op_rel.Create(emp_tbl,attribs);returnedit_op_rel.Execute();}returnfalse;//Create of entities failed});
Create a new Relationship and New Entities 2
varcreateRel=awaitQueuedTask.Run(()=>{//This example uses a KnowledgeGraphRelationshipDescriptionvaredit_op=newEditOperation(){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 Organizationattribs["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 Personattribs["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=newRowHandle(rowtoken_org);vardest_row_handle=newRowHandle(rowtoken_person);//Add any extra attribute information for the relation as neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);varrel_desc=newKnowledgeGraphRelationshipDescription(src_row_handle,dest_row_handle,attribs);//Add the relate description to the edit operationedit_op.Create(rel_stbl,rel_desc);//Execute the create of the entities and relationshipreturnedit_op.Execute();});
Create a Provenance Record
awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){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 nameattribs[ppi.ProvenanceFieldNamePropertyName]="name";//Must be a property/field on the entityattribs[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 nullattribs[ppi.ProvenanceCommentPropertyName]="Rock star";//can be anything - can be null//Add in the id of the provenance owner - our "person" in this caseattribs[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 rowedit_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(varentity_typeinentity_types){varrole=entity_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnentity_type.Value.GetName();}return"";}internalstaticstringGetHasDocumentTypeName(KnowledgeGraphDataModelkg_dm){varrel_types=kg_dm.GetRelationshipTypes();foreach(varrel_typeinrel_types){varrole=rel_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnrel_type.Value.GetName();}return"";}internalasyncvoidAddDocumentRecord(){awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph()){varedit_op=newEditOperation(){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;//optionalattribs["fileExtension"]=System.IO.Path.GetExtension(url);attribs["text"]=System.IO.File.ReadAllText(url);//optional and arbitrary - your choiceattribs["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=newQueryFilter(){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 rowattribs.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;//entityattribs[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);returnedit_op_rel.Execute();}}returnfalse;});}
Modify an Entity and Relationship record
awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){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=newQueryFilter(){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 updatedattribs["Name"]="Acme Ltd.";attribs["Description"]="Specializes in household items";attribs["SHAPE"]=org_updated_location;//Add to the edit operationedit_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=newQueryFilter(){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 operationattribs.Clear();//we are going to re-use the dictionaryattribs["StartDate"]=newDateTimeOffset(DateTime.Now);attribs["custom_attrib"]="Foo";attribs["custom_attrib2"]="Bar";//Add to the edit operationedit_op.Modify(rel_stbl,rel_oid,attribs);}//do the update(s)if(edit_op.Execute()){//TODO: Operation succeeded}});
Delete an Entity record
awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){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=newQueryFilter(){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
awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){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
awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){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=newKnowledgeGraphRelationshipDescription(guidOrigin,guidDestination);edit_op.Delete(rel_stbl,rd);edit_op.Execute();//Do the delete});
Schema Edits
Create Entity and Relationship Types with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";varrelate_name="WhoCalledWho";//Entity Fieldsvardescs1=newList<KnowledgeGraphPropertyDescription>();descs1.Add(newKnowledgeGraphPropertyDescription("PhoneOwner",FieldType.String));descs1.Add(newKnowledgeGraphPropertyDescription("PhoneNumber",FieldType.String));descs1.Add(newKnowledgeGraphPropertyDescription("LocationID",FieldType.BigInteger));descs1.Add(newKnowledgeGraphPropertyDescription("DateAndTime",FieldType.Date));//Relate Fieldsvardescs2=newList<KnowledgeGraphPropertyDescription>();descs2.Add(newKnowledgeGraphPropertyDescription("Foo",FieldType.String));descs2.Add(newKnowledgeGraphPropertyDescription("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=newShapeDescription(GeometryType.Point,sr){HasM=hasM,HasZ=hasZ};entityDesc=newKnowledgeGraphEntityTypeDescription(entity_name,descs1,shp_desc);relateDesc=newKnowledgeGraphRelationshipTypeDescription(relate_name,descs2,shp_desc);}else{entityDesc=newKnowledgeGraphEntityTypeDescription(entity_name,descs1);relateDesc=newKnowledgeGraphRelationshipTypeDescription(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
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph()){if(kg==null)return;varentity_name="PhoneCall";varrelate_name="WhoCalledWho";varentityDesc=newKnowledgeGraphEntityTypeDescription(entity_name);varrelateDesc=newKnowledgeGraphRelationshipTypeDescription(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
awaitQueuedTask.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(varpropinentity_props){if(prop.FieldType==FieldType.Geometry){continue;//skip shape}varprop_desc=newKnowledgeGraphPropertyDescription(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=newShapeDescription(shape_name,geom_def.geometryType,geom_def.sr);}//add the new entity propertyprop_descs.Add(KnowledgeGraphPropertyDescription.CreateStringProperty("foo",10));//make a description for the entity type - ok if shape_desc is nullvarentityDesc=newKnowledgeGraphEntityTypeDescription(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(varpropinrel_props){if(prop.FieldType==FieldType.Geometry){continue;//skip shape}varprop_desc=newKnowledgeGraphPropertyDescription(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=newShapeDescription(shape_name,geom_def.geometryType,geom_def.sr);}//add a new relationship propertyrel_prop_descs.Add(KnowledgeGraphPropertyDescription.CreateStringProperty("bar",10));//make a description for the relationship type - ok if shape_desc is nullvarrelDesc=newKnowledgeGraphRelationshipTypeDescription(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
awaitQueuedTask.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=newTableDescription(entity_table_def);varentity_table_flds=entity_table_def.GetFields();AttributeIndexDescriptionattr_index1=null;AttributeIndexDescriptionattr_index2=null;foreach(varfldinentity_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=newAttributeIndexDescription("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=newAttributeIndexDescription("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
awaitQueuedTask.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=newTableDescription(entity_table_def);varindexes=entity_table_def.GetIndexes();foreach(varidxinindexes){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=newAttributeIndexDescription(idx1,entity_table_desc);sb.Delete(idx_attr);}if(idx2!=null){varidx_attr=newAttributeIndexDescription(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
awaitQueuedTask.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=newCodedValueDomainDescription("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=newRangeDomainDescription("ShelfLife",FieldType.Integer,0,14);varsb=newSchemaBuilder(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=newArcGIS.Core.Data.DDL.FieldDescription("FruitTypes",FieldType.String);fruit_types_fld.SetDomainDescription(fruit_cvd_desc);//ShelfLife will use the range domainvarshelf_life_fld=newArcGIS.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=newFeatureClassDescription(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=newFeatureClassDescription(entity_name,modified_fld_descs,fruit_fc_desc.ShapeDescription);//Add the modified fruit fc desc to the schema buildersb.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
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph()){if(kg==null)return;//Get all the domains in the KGvardomains=kg.GetDomains();varsb=newSchemaBuilder(kg);foreach(vardomainindomains){//skip the special provenance domainvarname=domain.GetName();if(string.Compare(name,"esri__provenanceSourceType",true)==0)continue;//skip this one//Delete all other domainsif(domainisRangeDomainrd)sb.Delete(newRangeDomainDescription(rd));elseif(domainisCodedValueDomaincvd)sb.Delete(newCodedValueDomainDescription(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());}}});