Attribute rule isn't triggered when field is updated in a feature

867
5
Jump to solution
03-21-2023 12:10 PM
Labels (2)
PeterDouglas
New Contributor II

Hello,

I have a 1:M relationship class that relates a residences wastewater load (gallons) to the basin they reside in.  I created a field (TGallons) in the basin feature (Basins_Pop_Employ_2021_22_TESTENV) with a calculation attribute rule to be populated with the total gallons of all residences in that basin.  As an attribute rule, the field (TGallons) will not populate when features are added to the relationship class, are modified/updated, or deleted from it.  If I use the same Arcade expression in field calculator, the field will populate with the total number of gallons for the related customers.  Why would the attribute rule not trigger?  The arcade expression I used is shown below.

 

var related = FeatureSetByRelationshipName($feature, "Basins_Pop_Employ_2021_22_TESTENV_CAF_Addresses_TESTENV")

return sum(related, "gallons")

 

 

Any help would be appreciated.

Thanks!

0 Kudos
2 Solutions

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

You created the rule on the basin fc. This rule will only be executed if you change a basin feature. It will do nothing when you change the related table.

To do what you want, you have to create an Attribute Rule on the related table that changes the basin fc. You can do that by returning a dictionary instead of a single value. Documentation of that dictionary can be found here: Attribute rule dictionary keywords—ArcGIS Pro | Documentation

 

Something like this should work (untested!). Edit lines 7&8 to use the actual field you use for the relationship instead of BasinID!

// Calculation Attribute Rule on the customer table
// field: leave empty
// triggers: insert, update, delete
// exclude from application evaluation

// get all features belonging to the same basin
var basin_id = $feature.BasinID
var query = "BasinID = @basin_id"
if($editcontext.editType == "DELETE") {
    // exclude this feature if we're deleting it
    var oid = $feature.OBJECTID
    query += " AND OBJECTID <> @oid"
}
var wastewater_loads = Filter($featureset, query)

// get the total
var total_gallons = Sum(wastewater_loads, "gallons")

// get the related basin
var basin = First(FeaturesetByRelationshipName("Basins_Pop_Employ_2021_22_TESTENV")
if(basin == null) { return }

// return the dictionary to edit the basin fc
return {
    edit: [{
        className: "Basins_Pop_Employ_2021_22_TESTENV",
        updates: [{
            objectID: basin.OBJECTID,
            attributes: {TGallons: total_gallons}
        }]
    }]
}

 


Have a great day!
Johannes

View solution in original post

JohannesLindner
MVP Frequent Contributor

Yes, you need to do both edits in the same dictionary.

To do that, it's best to restructure the expression a little:

// get all features belonging to the same basin and sewer extension
var basin_id = $feature.Basin_ID
var ba_query = "Basin_ID = @basin_id"
var extension = $feature.Extension
var se_query = "Extension = @extension"

if($editcontext.editType == "DELETE") {
    // exclude this feature if we're deleting it
    var ba_gid = $feature.GlobalID
    ba_query += " AND GlobalID <> @ba_gid"
    var se_gid = $feature.GlobalID
    se_query += " AND GlobalID <> @SE_gid"
}
var wastewater_loads = Filter($featureset, ba_query)
var sewer_loads = Filter($featureset, se_query)

// get the total
var ba_total_gallons = Sum(wastewater_loads, "gallons")
var se_total_gallons = Sum(sewer_loads, "gallons")

// construct the edit array
var edit = []
var basin = First(FeaturesetByRelationshipName($feature, "Basins_CAF"))
if(basin != null) {
    var basin_edit = {
        className: "Basins",
        updates: [{
            globalID: basin.GlobalID,
            attributes: {TGallons: ba_total_gallons}
        }]
    }
    Push(edit, basin_edit)
}
var sewer = First(FeaturesetByRelationshipName($feature, "Sewer_by_CAF"))
if(sewer != null) {
    var sewer_edit = {
        classname: "Sewer_Extensions",
        updates: [{
             globalID: sewer.GlobalID,
             attributes: {CafCAP: se_total_gallons}
        }]
    }
    Push(edit, sewer_edit)
}

// return the dictionary to edit feature classes
return {edit: edit}

 

Note: You're missing a space before AND in the query in line 12!


Have a great day!
Johannes

View solution in original post

0 Kudos
5 Replies
JohannesLindner
MVP Frequent Contributor

You created the rule on the basin fc. This rule will only be executed if you change a basin feature. It will do nothing when you change the related table.

To do what you want, you have to create an Attribute Rule on the related table that changes the basin fc. You can do that by returning a dictionary instead of a single value. Documentation of that dictionary can be found here: Attribute rule dictionary keywords—ArcGIS Pro | Documentation

 

Something like this should work (untested!). Edit lines 7&8 to use the actual field you use for the relationship instead of BasinID!

// Calculation Attribute Rule on the customer table
// field: leave empty
// triggers: insert, update, delete
// exclude from application evaluation

// get all features belonging to the same basin
var basin_id = $feature.BasinID
var query = "BasinID = @basin_id"
if($editcontext.editType == "DELETE") {
    // exclude this feature if we're deleting it
    var oid = $feature.OBJECTID
    query += " AND OBJECTID <> @oid"
}
var wastewater_loads = Filter($featureset, query)

// get the total
var total_gallons = Sum(wastewater_loads, "gallons")

// get the related basin
var basin = First(FeaturesetByRelationshipName("Basins_Pop_Employ_2021_22_TESTENV")
if(basin == null) { return }

// return the dictionary to edit the basin fc
return {
    edit: [{
        className: "Basins_Pop_Employ_2021_22_TESTENV",
        updates: [{
            objectID: basin.OBJECTID,
            attributes: {TGallons: total_gallons}
        }]
    }]
}

 


Have a great day!
Johannes
PeterDouglas
New Contributor II

Thank you very much, this was extremely helpful!  I just had to switch from object ID to Global ID, and modify line 20 to read as shown below.  

 

var basin = First(FeaturesetByRelationshipName($feature, "Basins_Pop_Emply_2021_220TESTENV"))

 

0 Kudos
PeterDouglas
New Contributor II

This code worked well and I wanted to use it to update a different related table (2 related tables total) from the same field (gallons), while still updating the original table.  What I have now will only update the Basin feature class, but not the Sewer Extension class.  Do I need to include both updates in the same dictionary?  

I created/renamed features and relationships from the previous post to make them easier to work with.

// get all features belonging to the same basin and sewer extension
var basin_id = $feature.Basin_ID
var ba_query = "Basin_ID = @basin_id"
var extension = $feature.Extension
var se_query = "Extension = @extension"

if($editcontext.editType == "DELETE") {
    // exclude this feature if we're deleting it
    var ba_gid = $feature.GlobalID
    ba_query += " AND GlobalID <> @ba_gid"
    var se_gid = $feature.GlobalID
    se_query += "AND GlobalID <> @SE_gid"
}
var wastewater_loads = Filter($featureset, ba_query)
var sewer_loads = Filter($featureset, se_query)

// get the total
var ba_total_gallons = Sum(wastewater_loads, "gallons")
var se_total_gallons = Sum(sewer_loads, "gallons")

// get the related features
var basin = First(FeaturesetByRelationshipName($feature, "Basins_CAF"))
if(basin == null) { return }

// return the dictionary to edit feature classes
return {
    edit: [{
        className: "Basins",
        updates: [{
            GlobalID: basin.GlobalID,
            attributes: {TGallons: ba_total_gallons}
        }]
    }]
}

var sewer = First(FeaturesetByRelationshipName($feature, "Sewer_by_CAF"))
if(sewer == null) { return }

return {
    edit: [{
        classname: "Sewer_Extensions",
        updates: [{
             GlobalID: sewer.GlobalID,
             attributes: {CafCAP: se_total_gallons}
           }]
       }]
 }

 

0 Kudos
JohannesLindner
MVP Frequent Contributor

Yes, you need to do both edits in the same dictionary.

To do that, it's best to restructure the expression a little:

// get all features belonging to the same basin and sewer extension
var basin_id = $feature.Basin_ID
var ba_query = "Basin_ID = @basin_id"
var extension = $feature.Extension
var se_query = "Extension = @extension"

if($editcontext.editType == "DELETE") {
    // exclude this feature if we're deleting it
    var ba_gid = $feature.GlobalID
    ba_query += " AND GlobalID <> @ba_gid"
    var se_gid = $feature.GlobalID
    se_query += " AND GlobalID <> @SE_gid"
}
var wastewater_loads = Filter($featureset, ba_query)
var sewer_loads = Filter($featureset, se_query)

// get the total
var ba_total_gallons = Sum(wastewater_loads, "gallons")
var se_total_gallons = Sum(sewer_loads, "gallons")

// construct the edit array
var edit = []
var basin = First(FeaturesetByRelationshipName($feature, "Basins_CAF"))
if(basin != null) {
    var basin_edit = {
        className: "Basins",
        updates: [{
            globalID: basin.GlobalID,
            attributes: {TGallons: ba_total_gallons}
        }]
    }
    Push(edit, basin_edit)
}
var sewer = First(FeaturesetByRelationshipName($feature, "Sewer_by_CAF"))
if(sewer != null) {
    var sewer_edit = {
        classname: "Sewer_Extensions",
        updates: [{
             globalID: sewer.GlobalID,
             attributes: {CafCAP: se_total_gallons}
        }]
    }
    Push(edit, sewer_edit)
}

// return the dictionary to edit feature classes
return {edit: edit}

 

Note: You're missing a space before AND in the query in line 12!


Have a great day!
Johannes
0 Kudos
PeterDouglas
New Contributor II

Thank you very much! I had quite a hard time trying to figure that out.

0 Kudos