Hi,
This is my system configuration:
ArcGIS Pro 2.8
Electric Utility Network Version 4
ArcGIS Enterprise 10.8.1
SQL Server 2017
I'm trying to create a junction-junction connectivity association between a feature (with terminals) of the ElectricDevice class and another of the ElectricJunction class using attribute rules. I've searched the documentation (https://pro.arcgis.com/en/pro-app/latest/help/data/geodatabases/overview/attribute-rule-dictionary-k...) and followed some examples (https://github.com/Esri/arcade-expressions/blob/master/attribute_rule_calculation/CreateAttachmentAs... and https://github.com/Esri/arcade-expressions/blob/master/attribute_rule_calculation
/CreateAssociation.md ) in the arcade-expressions github repo; but my rule is not creating the association.
The rule is triggered when a feature (Riser with AssetType = 103) from the ElectricJunction class is inserted, then the rule look for a feature (Fuse with AssetType = 565) from the ElectricDevice class to create a connectivity association with the terminal "SS:S2" of the Fuse. If there is not Fuse near the Riser then the rule search for a feature (Line End with AssetType = 100) from the ElectricJunction class an creates connectivity association between the Riser and the Line End instead.
Here are the 2 versions of the code that I've tested:
// Assigned To: ElectricJunction
// Name: Proximity_Connectivity_Association
// Description: Upon insertion of an ElectricJunction of the allowed AssetTypes
// creates the connectivity association to the closest ElectricDevice MV Fuse or
// MV ElectricJunction Line End
// Subtypes: All
// Field: notes
// Execute: Insert
// Exclude from application evaluation: True
// ************* User Variables *************
// This section has the functions and variables that need to be adjusted based on your implementation
// The field the rule is assigned to
var field_value = $feature.notes;
var association_class = null;
var search_distance = 100;
var search_unit = 'feet';
var feat_globalid = $feature.globalID;
var valid_asset_types = [103];
// ************* End User Variables Section *************
if (indexof(valid_asset_types, $feature.assettype) == -1) {
return field_value;
}
//Find the closest MV Fuse
var fsDevices = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricDevice',["GLOBALID"], true)
var fBuffer = Buffer(Geometry($feature), search_distance, search_unit)
var fsClosest = Intersects(fsDevices, fBuffer)
var fsFuses = Filter(fsClosest, 'ASSETTYPE = 565') //565 = MV Fuse\Overhead Cutout Fused Load Break
var minDistance = Infinity
if (Count(fsFuses) <= 0) {
var fsElecJunction = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricJunction',["GLOBALID"], true)
fsClosest = Intersects(fsElecJunction, fBuffer)
var fsLineEnd = Filter(fsClosest, 'ASSETTYPE = 100') //100 = MV Line End\Overhead Line End
if (Count(fsLineEnd) <= 0) {
return field_value
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricJunction'
var closestle = null // closest MV Line End feature
for (var p in fsLineEnd) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestle = p
}
}
}
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricDevice'
var closestf = null // closest MV Fuse feature
for (var p in fsfuses) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestf = p
}
}
}
if (!IsEmpty(closestf)) {
var assocation_update = [{'globalID': closestf.globalID, 'fromTerminal': 'SS:S2' ,'associationType': 'connected'}];
} else if (!IsEmpty(closestle)) {
var assocation_update = [{'globalID': closestle.globalID, 'associationType': 'connected'}];
}else {
return field_value;
}
var edit_payload = [{'className': association_class, 'updates': assocation_update}];
return {
"result": field_value,
"edit": edit_payload
};
// *************************************************************************************************************************
// Assigned To: ElectricJunction
// Name: Proximity_Connectivity_Association
// Description: Upon insertion of an ElectricJunction of the allowed AssetTypes
// creates the connectivity association to the closest ElectricDevice MV Fuse or
// MV ElectricJunction Line End
// Subtypes: All
// Field: notes
// Execute: Insert
// Exclude from application evaluation: True
// ************* User Variables *************
// This section has the functions and variables that need to be adjusted based on your implementation
// The field the rule is assigned to
var field_value = $feature.notes;
var association_class = null;
var search_distance = 100;
var search_unit = 'feet';
var feat_globalid = $feature.globalID;
var valid_asset_types = [103];
// ************* End User Variables Section *************
if (indexof(valid_asset_types, $feature.assettype) == -1) {
return field_value;
}
//Find the closest MV Fuse
var fsDevices = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricDevice',["GLOBALID"], true)
var fBuffer = Buffer(Geometry($feature), search_distance, search_unit)
var fsClosest = Intersects(fsDevices, fBuffer)
var fsFuses = Filter(fsClosest, 'ASSETTYPE = 565') //565 = MV Fuse\Overhead Cutout Fused Load Break
var minDistance = Infinity
if (Count(fsFuses) <= 0) {
var fsElecJunction = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricJunction',["GLOBALID"], true)
fsClosest = Intersects(fsElecJunction, fBuffer)
var fsLineEnd = Filter(fsClosest, 'ASSETTYPE = 100') //100 = MV Line End\Overhead Line End
if (Count(fsLineEnd) <= 0) {
return field_value
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricJunction'
var closestle = null // closest MV Line End feature
for (var p in fsLineEnd) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestle = p
}
}
}
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricDevice'
var closestf = null // closest MV Fuse feature
for (var p in fsfuses) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestf = p
}
}
}
if (!IsEmpty(closestf)) {
var association_update = [{
'fromnetworksourceid': 'UN_MODEL_V34.MODEL_V34.ElectricDevice',
'fromglobalid': closestf.globalID,
'fromterminalid': 1,
'tonetworksourceid': 'UN_MODEL_V34.MODEL_V34.ElectricJunction',
'toglobalid': $feature['globalid'],
'toterminalid': 1,
'associationtype': 1,
'iscontentvisible': 0,
'globalid': Guid()
}
]
} else if (!IsEmpty(closestle)) {
var assocation_update = [{'globalID': closestle.globalID, 'associationType': 'connected'}];
}else {
return field_value;
}
var edit_payload = [{'className': association_class, 'adds': assocation_update}];
return {
"result": field_value,
"edit": edit_payload
};
Solved! Go to Solution.
Hey Billy
I suggest reading the blog I authored on this topic. It has basic examples of creating associations of all types using attribute rules. The rule you have is so large to debug without the data. I suggest starting with a simpler rule to narrow down whats wrong. It might help to work with a file geodatabase so altering and testing the rule is easier. Then deploy it to enterprise.
Do you get an error when inserting a feature or does it work but doesn't create the connection?
One thing I noticed: Your association_updates are wrong.
An update is defined as
{"globalID": "GUID-of-the-updated-feature", "attributes": {"Field1": "Value1", "Field2": "Value2"}}
So your line 69 (use accordingly for lines 71, 162, 176) should be
//var assocation_update = [{'globalID': closestf.globalID, 'fromTerminal': 'SS:S2' ,'associationType': 'connected'}];
var assocation_update = [{'globalID': closestf.globalID, 'attributes': {'fromTerminal': 'SS:S2' ,'associationType': 'connected'}}];
Hi Johannes,
Thanks for your reply.
Code:
if (!IsEmpty(closestf)) {
var assocation_update = [{'globalID': closestf.globalID, 'fromTerminal': 'SS:S2' ,'associationType': 'connected'}];
} else if (!IsEmpty(closestle)) {
var assocation_update = [{'globalID': closestle.globalID, 'associationType': 'connected'}];
}else {
return field_value;
}
var edit_payload = [{'className': association_class, 'updates': assocation_update}];
return {
"result": field_value,
"edit": edit_payload
};
Error message trying to Create Association between the Riser and the Fuse with terminals (line 2 of code above):
Error in Pro:
Successful when trying to Create Association between the Riser and the Line End (line 4 of the code above), and I'm not using the "attributes" keyword in the dictionary as you suggest:
2. Behavior with your suggestion to include the "attributes" keyword in the dictionary:
Code:
if (!IsEmpty(closestf)) {
var assocation_update = [{'globalID': closestf.globalID, 'attributes': {'fromTerminal': 'SS:S2' ,'associationType': 'connected'}}];
} else if (!IsEmpty(closestle)) {
var assocation_update = [{'globalID': closestle.globalID, 'associationType': 'connected'}];
}else {
return field_value;
}
var edit_payload = [{'className': association_class, 'updates': assocation_update}];
return {
"result": field_value,
"edit": edit_payload
};
Error message trying to Create Association between the Riser and the Fuse with terminals (line 2 of code above):
Successful when trying to Create Association between the Riser and the Line End (line 4 of the code above), and I'm not using the "attributes" keyword in the dictionary as you suggest:
My conclusion at this point is that the documentation explaining the syntax of the dictionary should be expanded with better examples on how to create the different associations (connectivity, attachment and containment) between the utility network features with and without terminal. Also, I'm not sure if I have to use the keyword "adds" or "updates". One of the examples in the arcade-expressions github page uses "adds" to create new association (https://github.com/Esri/arcade-expressions/blob/master/attribute_rule_calculation/CreateAssociation....); the other uses "updates" (https://github.com/Esri/arcade-expressions/blob/master/attribute_rule_calculation/CreateAttachmentAs...). Also, notice that none of these sample codes use the keyword "attributes" in the returned dictionary.
Ah, my bad. I thought fromTerminal and associationType were attributes, but they seem to be keywords of the utility network.
Hey Billy
I suggest reading the blog I authored on this topic. It has basic examples of creating associations of all types using attribute rules. The rule you have is so large to debug without the data. I suggest starting with a simpler rule to narrow down whats wrong. It might help to work with a file geodatabase so altering and testing the rule is easier. Then deploy it to enterprise.
Hi Hussein,
Thanks for the link to the blog, it was very useful. It looks like this blog is not part of the "Attribute Rules" forum because I did several searches before starting this question to see if there was a blog or previous questions related to this topic.
After following the examples in the blog I was able to find that the problem with my original rule was that I was using the keyword "fromTerminal" instead of "toTerminal" to connect to the "SS:S2" terminal of the Fuse feature. Here is the correct code:
// Assigned To: ElectricJunction
// Name: Proximity_Connectivity_Association
// Description: Upon insertion of an ElectricJunction of the allowed AssetTypes
// creates the connectivity association to the closest ElectricDevice MV Fuse or
// MV ElectricJunction Line End
// Subtypes: All
// Field: notes
// Execute: Insert
// Exclude from application evaluation: True
// ************* User Variables *************
// This section has the functions and variables that need to be adjusted based on your implementation
// The field the rule is assigned to
var field_value = $feature.notes;
var association_class = null;
var search_distance = 100;
var search_unit = 'feet';
var feat_globalid = $feature.globalID;
var valid_asset_types = [103]; // 103 = MV Line End\Riser
// ************* End User Variables Section *************
if (indexof(valid_asset_types, $feature.assettype) == -1) {
return field_value;
}
//Find the closest MV Fuse
var fsDevices = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricDevice',["GLOBALID"], false)
var fBuffer = Buffer(Geometry($feature), search_distance, search_unit)
var fsClosest = Intersects(fsDevices, fBuffer)
var fsFuses = Filter(fsClosest, 'ASSETTYPE = 565') //565 = MV Fuse\Overhead Cutout Fused Load Break
var minDistance = Infinity
if (Count(fsFuses) <= 0) {
var fsElecJunction = FeatureSetByName($datastore, 'UN_MODEL_V34.MODEL_V34.ElectricJunction',["GLOBALID"], false)
fsClosest = Intersects(fsElecJunction, fBuffer)
var fsLineEnd = Filter(fsClosest, 'ASSETTYPE = 100') //100 = MV Line End\Overhead Line End
if (Count(fsLineEnd) <= 0) {
return field_value
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricJunction'
var closestle = null // closest MV Line End feature
for (var p in fsLineEnd) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestle = p
}
}
}
} else {
association_class = 'UN_MODEL_V34.MODEL_V34.ElectricDevice'
var closestf = null // closest MV Fuse feature
for (var p in fsfuses) {
var pDistance = Distance(p, $feature, 'feet')
if (pDistance < minDistance) {
minDistance = pDistance;
closestf = p
}
}
}
if (!IsEmpty(closestf)) {
var assocation_update = [{'globalID': closestf.globalID, 'toTerminal': 'SS:S2' ,'associationType': 'connected'}];
} else if (!IsEmpty(closestle)) {
var assocation_update = [{'globalID': closestle.globalID, 'associationType': 'connected'}];
}else {
return field_value;
}
var edit_payload = [{'className': association_class, 'updates': assocation_update}];
return {
"result": field_value,
"edit": edit_payload
};