BPM C# "The Specified field has changed from any to another"

Hello, I’ve tested the code below in a Data Directive “in-transaction” and in Method Directive “pre-processing” and it works in both
It checks if a specific field has changed from any to another
Can anyone see any improvements that could be made??

bool fieldChange = (ttJobHead.Any(r => r.Updated() && ttJobHead.Any(r1 => r1.SysRowID == r.SysRowID && r1.Unchanged() && (r1.ReqDueDate != (r.ReqDueDate)))));
                        
                        if(fieldChange == true) // or == false or != null
                        {
                        // this is where you do the action
                        
                        }
2 Likes

Wow… i love the simplicity. I have done this before, but with two different queries and then a comparison.

I did try a few different changes… option 1; i simply reduced the number of parenthesis as they were not needed. I also broke the line up so that it was easier to see which variable needed changed. Then… I made the bool variable name more specific for “which field changed”…
Oh… one other simplification I made was in the IF statement… "If (fieldChange == true) is a comparison that is redundant… it is like saying “If True == True”… instead you can just say “If (fieldChange)” becuase fieldChange will be either True or False. If you want to check for a false value, you can say “if (!fieldChange)” with an Exclamation point which means “Not”.

bool ReqDueDate_fieldChanged =
    ttJobHead.Any(r => r.Updated() &&
    ttJobHead.Any(r1 => r1.Unchanged() && r1.SysRowID == r.SysRowID &&
    r1.ReqDueDate != r.ReqDueDate));

if (ReqDueDate_fieldChanged) {
    // this is where you do the action if it is changed
}
if (!ReqDueDate_fieldChanged) {
    // this is where you do the action if it is not changed
}

Then I thought: "Hey… why “always” run this… maybe we only need to run the query on command. So, i played with changing the query to a c# Func… now it only runs the query if it is used in a condition. This is GOOD if you are only checking the condition one time… but it is BAD if you have multiple “if” statements that need to find out if the value has changed.

//using a function to decide if a field has changed
Func<bool> ReqDueDate_fieldChanged = () => {
    return ttJobHead.Any(r => r.Updated() &&
        ttJobHead.Any(r1 => r1.Unchanged() && r1.SysRowID == r.SysRowID &&
        r1.ReqDueDate != r.ReqDueDate));
};

if (ReqDueDate_fieldChanged()) {
    // this is where you do the action
}

Does the Condition Widget not do the same thing? Even if it does the check and then sets a variable before the Exec Custom Code widget?

image

yes, It DOES do the same thing… The challenge is that if you have 10 values you are checking for, this would get VERY cluttered with widgets. If it is just one value, the widget based code would be better.

@timshuwy and @ckrusen
Tim, thanks for the variations and refinements, I’m pretty new to C#, I used to use widgets for everything but the page gets cluttered very quickly

1 Like

My slightly different approach, using a join:

var fieldsToCheck = new List<string>() { "Field1", "Field2", "Field3" };
var fieldChanged = ttJobHead.Where(j => j.Updated())
                            .Join(ttJobHead.Where(oj => oj.Unchanged()),
                                  upd => upd.SysRowID,
                                  org => org.SysRowID,
                                  (upd, org) => new { Updated = upd, 
								                      Original = org })
                            .Any(r => fieldsToCheck.Any(f => r.Updated[f] != r.Original[f]));

For the record, I also prefer writing code to widgets usually… But to be fair, if you have 10 different fields you don’t need 10 condition widgets, just the one with 10 conditions with Or operators between them. The way I see it, if you’re gonna use a code block anyway, might as well put the condition in there so everything is in the same place…

2 Likes

Does the widget based approach have more overhead (at run time) than the code examples used?

Probably, since it needs to parse the fields into an expression, but it’s most likely negligible…

While hand coded is probably faster, I believe that when you enable the BPM, that’s the only time the widgets are parsed before it generates the code block which is used at runtime and looks no different than any other code block at that point - but I could be wrong about that.