Attribute Rules - Exclude from Application Evaluation

7198
10
04-08-2021 10:30 AM
HusseinNasser2
Esri Contributor
18 10 7,198

Attribute rules are scripts authored in Arcade and added to classes in the geodatabase to enforce constraints, calculate fields, query or edit classes in the same geodatabase. Many properties can be set while authoring attribute rules, the name of rule, subtypes the rule applies to, when to trigger the rule and yes Exclude from Application Evaluation. This option has raised many questions in the community so I thought I'd write a blog discussing the purpose of this property and when one should use it.


Attribute Rule Execution
Attribute rules are stored in the class, so wherever the geodatabase go, the rule goes with it. The rule always executes in the backend geodatabase datastore, whether you initiated the edit from Pro, Collector or Javascript API. Some applications are capable of understanding and executing the rule locally BEFORE the edit request is sent to the backend geodatabase datastore to be executed again.

 

Application vs Backend

It is important to differentiate between the application and the backend geodatabase workspace. ArcGIS Pro is an application and feature service, file or mobile geodatabase, enterprise geodatabase are the backend geodatabase workspace.

So if I add my filegdb class to Pro and edited the class, Pro can perform the edit locally before "sending" the edit request to the filegdb workspace. This concept is applied to any workspace, services, enterprise geodatabase, mobile geodatbase and file geodatabase.

You can see this behavior in Pro's attribute pane window while the Auto Apply option is turned off. Here is an example where we have an attribute rule that adds field a to field b and store the value in field c. The rule has allowed for application evaluation.

HusseinNasser2_0-1617901692407.png

exclude.gif

Exclude from Application Evaluation
When unchecked, "Exclude from Application Evaluation" property tells the application that its "safe" to execute this rule locally before sending the edit request to the backend. So you get the behavior like the attribute pane in place execution without the need to persist your edit to the backend to see the rules effects. Smart applications can look at this property and decide to leverage local attribute rule execution if it supports it. As for the time writing this blog, ArcGIS Pro is the only application that is capable of executing attribute rules locally.

Here is the same rule from before but with Exclude from Application Evaluation turned on. Noticed that local edits in the pane does not trigger the attribute rule until applying the edit to the workspace.

 

HusseinNasser2_1-1617901950204.png

 

 

 

excludeYES.gif

 

Constraint rules benefit the most from having the application execute the rule locally. If the application executes the constraint rule locally and finds that the rule is violated, an applyEdits request is never sent to the server since we know the request is going to fail there too. This saves on network bandwidth in certain case. Note that the constraint rule is always re-executed on the server side.

Another benefit of allowing the application to execute the rule locally is offloading heavy attribute rule compute to the application (when applicable) and only send the final result to the backend. The attribute rule has to be written in such a way to allow for the server to skip computation that has been already performed in the client. This way the server consumes less resources and editing throughput improves.

 

When to Exclude my Rule from Application Evaluation?

There are use cases where you want to exclude a rule from application evaluation here are a few.

Application doesn't support certain Arcade functionality
Even if the application is capable of executing attribute rules locally, not all Arcade functionalities are applicable for local execution. Examples are the attribute rules DML ability to edit other features, and working with sequences NextSequenceValue. Attribute rules that use these functionalities must be excluded from client evaluation.

Application doesn't have access to tables behind service

The application can sometimes have access to only a subset of classes of the backend geodatabase. Lets say a geodatabase has 3 classes class1,class2, class3. A feature service is published from this geodatabase but only class1 and class2 are included as layers. This means an application consuming the feature service only has direct access to class1 and class2 and NOT class3. If there is an attribute rule on class1 that was allowed to be executed locally (exclude from application evaluation was turned off) and that rule is querying class3, that rule will fail because the application wouldn't find class3 in its local workspace. You might have seen this error before "Arcade Error: Table not found"  followed by a guid, that error becomes clear once you understand what really is happening. For such cases you need to exclude the rule from local execution, sending the edit to the backend server will eventually execute on the server geodatabase workspace which has access to all classes.

 

Final thoughts
If we go back to when we first designed this, I would definitely pick another name for this property. Maybe Allow Application Evaluation?

 

 

10 Comments
JohannesLindner
MVP Frequent Contributor

Thank you for this great explanation!

This is a parameter that always confused me, but ArcGIS always told me when to check that box, so I didn't research it.

 

The attribute rule has to be written in such a way to allow for the server to skip computation that has been already performed in the client.

Sure, if I calculated a+b locally to improve throughput on the server, it would be senseless to have the server do it again. But how do you write such a rule? I don't see a way to tell the server that your example rule was already executed.

In my opinion, that should be part of the communication between client and server. When applying the edit, the client should tell the server it already did the job, so the server doesn't even have to start the execution to perform some checks built into the rule to see if it already executed.

 

HusseinNasser2
Esri Contributor

Hey Johannes,

In most cases you can tell if the rule has been executed if a value has been set to a certain field. In our example if $feature.c has changed that indicates that the client has already performed and persisted the value to c and is now sending us the value of c along side a and b.

We released a global $originalFeature that would allow you to compare the original value of the field compared to the new value that is about to get set. So subsequent edits to a and b will produce new c values and you can compare if $feature.c is not equal $originalFeature.c then it means the client has already performed the calculation.

Of course this isn't straight-forward to implement and there are other gotchas as well to be discussed like making sure the client doesn't just mock with the value of c directly by making the field read only or hidden.

The compute in our example here is obviously trivial but the logic is applicable to complex Arcade expressions in a similar fashion

vpelleritoCritigen
New Contributor II

Thanks for this helpful illustration.


"If we go back to when we first designed this, I would definitely pick another name for this property. Maybe Allow Application Evaluation?"

 

My thought exactly!

Thanks,

Vince

BrianBulla
Occasional Contributor III

Hi,

Does this have any effect on sharing layers to AGOL?  For example, if I have a rule on a related inspection table, that updates the parent feature whenever an insert or update happens, would the rule automatically trigger when sharing the data to AGOL?

I am finding that when creating a hosted feature service in AGOL, that the attributein my parent feature class is getting updated, and this is the only explanation I can think of.

See the last few posts on this thread if you want more background:

https://community.esri.com/t5/arcgis-pro-questions/symbolizing-unique-values-with-wildcards/m-p/1273...

 

 

solidsnake
New Contributor II

Hi

i have a probleme with attribute rule that execute twice in a feature service.

when i create record in arcgis pro through geodatabase evrything work perfectly for each record i create the ID increment by +1, but when i edit the data through  feature service in Arcgis Pro or with the Edit widget in web app builder its like the attribute rule is executing twice (URB00002, URB00004, URB00006....) +2 for each new record.

 

Capture 2.PNG

 

i checked Exclude from Application Evaluation but it always fire twice

i tried to put max instance = 1 but it didn't work

the arcade code of the attribute rule in the feature service is the same as the geodatabase, the only difference is the name of the table: in database its  "oncf.dgf.urb_projet" and in feature service its "L2oncf_dgf_urb_projet"

capture of attribute rule in geodatabase

Capture geodatabase.PNG

capture of attribute rule in feature service

Capture feature service.PNG

i use ArcGis enterprise 10.7.1 and arcgis pro 3.0.1

is there a way i can fix this probleme

thanks for you help

SamSzotkowski
New Contributor III

@solidsnake I had not exactly the same, but a similar issue where attribute rules were creating 2 empty features every time a calculation or constraint rule returned an error.  I submitted a bug report and Esri said that got fixed in Pro 3.1.  So not quite the same thing, but sounds very similar so maybe yours got fixed with that update.

"Updates have been made to the following defect which you are associated with:
BUG-000155457 - The append tool surpasses Attribute rules (both constrain and calculation), adding two empty/null records to the target table per record that violates the rule."

SayedAamirHussain
New Contributor

Thank you so much @HusseinNasser2  for explanation, it really helped a lot. 

LindaGallion
New Contributor II

This is a great explanation. Thank you. I am trying to use the "Update Site Addresses" attribute rule from the Address Management Solution in a branch versioned feature service. I have edited it to fit my data but when I change a road name it doesn't seem to have any effect on the associated structures. Does having that box checked mean the changes won't take effect immediately? If so, when do they take effect? How do I know if it's working? Any guidance is greatly appreciated. Thank you!

HusseinNasser2
Esri Contributor

Thanks Linda,

You see rules often are downloaded to the client application (e.g. ArcGIS Pro) so when you make the edit the rule is executed in the application locally first (like Pro) then the modified row is sent to the backend (be it a service or geodatabase) where it will be executed again. 

so if this option is checked it means that this rule will execute on the backend and not locally in the application. So in the first case you will see the change immediately, while in the second case you will have to wait for the server/backend to finish processing your edit, built a service edits payload (things that has changed in the server) and return to the client application, the application then takes those changes and applies them locally to the display/caches where it will show up. So yes little delay but the delay is equal to the time of the actual edit.

hope that helps

There is a devsummit session I did where I go into that in details https://mediaspace.esri.com/media/t/1_gr7hrdjy 

LindaGallion
New Contributor II

Thank you. That was helpful. Based on your information I now realize there must be a problem with my code. I took it from the Address Management Solution. Can you tell by looking at this why my structures are not being updated when my road name changes? Nothing happens, no error message - nothing.

// This rule will run when the road name changes, find all site addresses that fall within the address range and update their road name

// Define Road Centerline fields
var fullname_field = "msagcomple";
var fromleft_field = "fromleft";
var fromright_field = "fromright";
var toleft_field = "toleft";
var toright_field = "toright";
var munileft_field = "commleft";
var muniright_field = "commright";

// Define the Site Addresses fields
var addressfullname_field = "msagcomple";
var addrnum_field = "address";
var municipality_field = "msagcommun";

// If the full road name is unchanged return;
If (!HasKey($feature, fullname_field)) return;
var fullname = $feature[fullname_field];
var origFullName = $originalFeature[fullname_field]
if (origFullName == fullname) return;

var fromLeft = $feature[fromleft_field];
var toLeft = $feature[toleft_field];
var fromRight = $feature[fromright_field];
var toRight = $feature[toright_field];

// This function will return the parity (0-0, Even, Odd, Both) given the from and to values of a side
function getParity(from, to) {
if (IsEmpty(from) || from == 0 || IsEmpty(to) || to == 0) {
if (from == 0 && to == 0) {
return ["0-0", 0, 0];
}
return ["Error", null, null];
}
var minval = Min([from, to]);
var maxval = Max([from, to]);

if (from % 2 == 0 && to % 2 == 0) return ["Even", minval, maxval];

if (from % 2 != 0 && to % 2 != 0) return ["Odd", minval, maxval];

return ["Both", minval, maxval];
}

function updateSiteAddress(updates, siteAddress) {
Push(updates, {
'globalID': siteAddress[globalid_field],
'attributes': Dictionary(addressfullname_field, fullname)
})
}

var parityLeft = getParity(fromLeft, toLeft);
var parityRight = getParity(fromRight, toRight);

// If the road has no odd or even ranges return
if (Includes(["0-0", "Error"], parityLeft[0]) && Includes(["0-0", "Error"], parityRight[0])) return;

// Find all site addresses that have the same road name as road name prior to the edit
// Add each matching site address to an array storing the global id and updated road name
var updates = []
var siteAddresses = Filter(FeatureSetByName($datastore, "regional_branch.sde.WCTCOGSiteStructurePoints", [addressfullname_field, addrnum_field, municipality_field, "globalid"], false), addressfullname_field + " = @origFullName");
var globalid_field = Schema(siteAddresses).globalIdField;
for (var siteAddress in siteAddresses) {
// Test if the address number is a number, if not continue
var addrnum = Number(siteAddress[addrnum_field])
if (isNaN(addrnum)) {
continue;
}

if (siteAddress[municipality_field] == $feature[munileft_field] && (addrnum >= parityLeft[1] && addrnum <= parityLeft[2])) {
if (parityLeft[0] == "Both") {
updateSiteAddress(updates, siteAddress);
}
else if (parityLeft[0] == "Odd" && addrnum % 2 != 0) {
updateSiteAddress(updates, siteAddress);
}
else if (parityLeft[0] == "Even" && addrnum % 2 == 0) {
updateSiteAddress(updates, siteAddress);
}
}

if (siteAddress[municipality_field] == $feature[muniright_field] && (addrnum >= parityRight[1] && addrnum <= parityRight[2])) {
if (parityRight[0] == "Both") {
updateSiteAddress(updates, siteAddress);
}
else if (parityRight[0] == "Odd" && addrnum % 2 != 0) {
updateSiteAddress(updates, siteAddress);
}
else if (parityRight[0] == "Even" && addrnum % 2 == 0) {
updateSiteAddress(updates, siteAddress);
}
}
}

// Using the edit parameter return the list of updates for the site address points
return {
'edit': [
{'className': 'regional_branch.sde.WCTCOGSiteStructurePoints', 'updates': updates}
]
};

About the Author
Software Engineer, Author of several GIS books and Software Engineering Content Creator on YouTube and Anchor.fm podcast