drools input validation and stop execution - validation

I have to validate some elements for null and then stop execution if they are null.
I have few rules like below which checks for some null values and adds errors
rule "Require begin date for Service Period"
salience 100
when
$servicePeriod : ServicePeriod(beginDate == null)
// check this to avoid the infinite loop
eval(!$servicePeriod.getValidationErrors().contains("Begin date is required."))
then
$servicePeriod.getValidationErrors().add("Begin date is required.");update($servicePeriod);
end
I have some rules like below which first checks 'validationErrors.size() == 0'. Even though validation errors size is greater than zero, it continues to check other validation and fails as they are null. Please let me know how I can modify these rules to avoid exception.
// Rules for Firefighter deduction calculation
rule "Firefighter Annual Salary Deposit Calculation"
salience 50
when
$servicePeriod : ServicePeriod(validationErrors.size() == 0 , periodType.name == "DEPOSIT" , payType.name == "ANNUAL SALARY" , serviceType.name == "FIREFIGHTER" )
then
calculateDeduction($servicePeriod, 0.075);
end

I suspect that you're thinking that in Java, such constraints are evaluated from left to right, so if the first constraint checks for 0 or null, then further constraints are safe. However, this is not the case in Drools comma-separated constraints.
I think that you might be able to switch to a more Java-style expression:
ServicePeriod(
validationErrors.size() == 0,
periodType != null && periodType.name == "DEPOSIT",
payType != null && payType.name == "ANNUAL SALARY",
serviceType != null && serviceType.name == "FIREFIGHTER" )
I'm not totally sure without testing though.

Related

Java Stream filter - how can i filter data without wrapping the filter code in 'if' condition for checking null on the filtering keys?

I am doing the following:
List<Objects> filtered = objects.stream()
.filter(o -> source.equals(o.getSource()) && date.equals(o.getDate()) && id.equals(o.getId()))
.collect(Collectors.toList());
where both date and id could possibiliy be null, as the are coming from method parameters.
How can I ignore them if null, without wrapping the above code in an if statement tp check 'id' and 'date' for null values ? I want to do it inside the filter.
Edit : To make it more clear, i want the filter to act only on the non-null values, i.e if date is non-null and id is null, then filter only on date and ignore id, and so on..
Thanks
An additional option is to do the null checks in the predicate:
.filter(o -> source.equals(o.getSource())
&& (null == date || date.equals(o.getDate()))
&& (null == id || id.equals(o.getId())))
You could use the static method Objects::equals. Chances are that this method is designed for just this:
List<Objects> filtered = objects.stream()
.filter(o -> Objects.equals(source, o.getSource()) && Objects.equals(date, o.getDate()) && Objects.equals(id, o.getId()))
.collect(Collectors.toList());
Note: as Scratte mentioned in the comments, this may not filter out objects for which getDate() returns null, if date is also null. Same goes for id. If that's the case, then the abovementioned code snippet does not comply. In that case, then we have to explicitly filter for non-null dates and ids:
.filter(o -> Objects.nonNull(o.getId()) && Objects.nonNull(o.getDate()))
Update
If you want to skip the comparison for getDate() if date is null (and same for id), then you could check first for null, just like in ernest_k's answer.
You could easily build a small method for it:
public static boolean nullOrEquals(Object baseObject, Object compareObject) {
return baseObject == null || Objects.equals(baseObject, compareObject);
}
.filter(o -> Objects.equals(source, o.getSource())
&& nullOrEquals(date, o.getDate())
&& nullOrEquals(id, o.getId()))
Here's an Ideone example.

PLSQL - Find two values are equal when they are NULL

I'm using a IF condition to check whether 2 values are equal or not. In one scenario all the values that I use are NULL, but it does not recognize as they are equal.
IF training_event_rec_.training_fee = course_rec_.course_fee AND training_event_rec_.training_fee_unit = course_rec_.course_fee_unit AND training_event_rec_.currency = course_rec_.currency AND training_evaluation_temp_ = course_evaluation_temp_ THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
In here all the variables that is compared are NULL but it always hit the ELSE part.
How Can I compare values in this kind of situations.
Use IS NULL:
IF (training_event_rec_.training_fee = course_rec_.course_fee OR
(training_event_rec_.training_fee IS NULL AND course_rec_.course_fee IS NULL))
AND (training_event_rec_.training_fee_unit = course_rec_.course_fee_unit OR
(training_event_rec_.training_fee_unit IS NULL AND course_rec_.course_fee_unit IS NULL))
AND (training_event_rec_.currency = course_rec_.currency OR
(training_event_rec_.currency IS NULL AND course_rec_.currency IS NULL))
AND (training_evaluation_temp_ = course_evaluation_temp_ OR
(training_evaluation_temp_ IS NULL AND course_evaluation_temp_ IS NULL))
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
NOTE:
You can also compare Nulls like NVL(COLUMN_A,'X') = NVL(COLUMN_B,'X') only if you are sure that COLUMN_A & COLUMN_B will not contain value 'X'. So that is not recommended approach.
I presume there might be different combinations of non-null and null values. One option is to check them all, or - maybe simpler - use NVL, such as:
IF nvl(training_event_rec_.training_fee, 0) = nvl(course_rec_.course_fee, 0)
AND nvl(training_event_rec_.training_fee_unit, 0) = nvl(course_rec_.course_fee_unit, 0)
AND nvl(training_event_rec_.currency, 0) = nvl(course_rec_.currency, 0)
AND nvl(training_evaluation_temp_, 0) = nvl(course_evaluation_temp_, 0)
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
Depending on datatypes, you might need to use something else, not 0. For example, currency might be USD or EUR or something like that, so you'd use
nvl(training_event_rec_.currency, 'x')

How to pass an external parameter to LINQ where clause in CRM

I have a LINQ query which works fine as for stand alone lists but fails for CRM
var lst = new List<bool?>();
lst.Add(null);
lst.Add(true);
lst.Add(false);
bool IsWet = false;
var newlst = from exch_HideVoiceSignature in lst where
(((exch_HideVoiceSignature!=null && exch_HideVoiceSignature==false
|| exch_HideVoiceSignature== null) )&& !IsWet) select exch_HideVoiceSignature;
newlst.Dump();
var question = from q in exch_questionSet where ((q.exch_HideVoiceSignature != null
&& q.exch_HideVoiceSignature.Value == 0 )|| q.exch_HideVoiceSignature == null )
&& !IsWet select q.exch_HideVoiceSignature;
question.FirstOrDefault().Dump();
As you can see I can pass the variable IsWet to LINQ query for a standard list fine and get values for first list. But when I execute the same for second list, I get the following error
Invalid 'where' condition. An entity member is invoking an invalid property or method
The CRM LINQ provider won't support the evaluation you attempting. It only supports evaluation of where criteria is evaluating an entity field.
That's not a problem. Since you want the LINQ query to only use the where clause if IsWet is false (correct me if I'm wrong on that.) So we simply do the evaluation to determine if the where clause should be added or not. Then execute your query.
var question = from q in exch_questionSet
select q.exch_HideVoiceSignature;
if (!IsWet)
{
question.Where(x => ((x.exch_HideVoiceSignature != null
&& x.exch_HideVoiceSignature.Value == 0) || x.exch_HideVoiceSignature == null));
}
question.FirstOrDefault().Dump();
I am constantly confronted with that problem.
Try to "detach" (for example call .ToArray()) your query (while it is "clear") from CRM and then filter query using external parameter. This should help.
var question =
(from q in exch_questionSet
where (
(q.exch_HideVoiceSignature != null && q.exch_HideVoiceSignature.Value == 0 ) ||
q.exch_HideVoiceSignature == null )
select q.exch_HideVoiceSignature
).ToArray().Where(q => !IsWet);
question.FirstOrDefault().Dump();
UPDATE
If you are using IsWet flag to control blocks of conditions (enable and disable them from the one point in the code) then probably you may be interested in class named PredicateBuilder which allows you to dynamically construct predicates.
Just because I had an existing query with lot of other joins etc. and I wanted to pass this additional parameter to it I ended up using a var statement which dumps the rows to a list and applies the where clause in the same statement
bool IsWet =true ;
var question = ...existing query ...
select new {
...existing output ...,
Wet =q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080001,
Voice = q.exch_HideVoiceSignature == null ||
(q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080000) ,
}
;
var qq = IsWet ?
question.ToList().Where(X=> X.Wet ) :
question.ToList().Where(X=> X.Voice );
qq.FirstOrDefault().Dump();

How Oracle 10g evaluates NULL in boolean expressions

if not (i_ReLaunch = 1 and (dt_enddate is not null))
How this epression will be evaluated in Oracle 10g
when the input value of the i_ReLaunch = null and the value of the dt_enddate is not null
it is entering the loop.
According to the rules in normal c# and all it should not enter the loop as
it will be as follows with the values.
If( not(false and (true))
= if not( false)
=if( true) which implies it should enters the loop
But it is not happening
Can someone let me know if i am wrong at any place
Boolean operations with NULL value in Oracle return UNKNOWN - not true or false. So you have something like this:
If( not(UNKNOWN and (true)) = if not( UNKNOWN) =if( UNKNOWN )
In this case, IF will treat UNKNOWN as false.
If i_relaunch can be null, then you need to use some of NULL handling functions(NVL, NVL2, NULLIF, COALESCE, LNNVL) to be sure that you have correct result.
See these article for more information:
Nulls: Nothing to Worry About
Fundamentals of PL/SQL. Scroll down to - Handling Null Values in Comparisons and Conditional Statements

Unpassable Where Clauses LINQ-to-SQL

As I'm struggling to learn LINQ I’ve managed to generate a SQL statement with "AND (0 = 1)" as part of the where clause. I'm just wondering if this result is common in poorly written queries and is a known issues to try and avoid or if I am doing something totally backwards to end up with this.
Update
public static IEnumerable<ticket> GetTickets(stDataContext db,string subgroup, bool? active)
{
var results = from p in db.tickets
where
( active == null || p.active == active )
/*(active == null ? true :
((bool)active ? p.active : !p.active))*/ &&
p.sub_unit == db.sub_units.Where(c=>subgroup.Contains(c.sub_unit_name))
select p;
return results;
}
If I ignore the active part and just run
public static IEnumerable<ticket> GetTickets1(stDataContext db,string subgroup, bool? active)
{
return db.tickets.Where(c => c.sub_unit.sub_unit_name == subgroup);
}
It returns the groups of tickets I want ignoring the active part.
I'd pull the processing out of the ternary operators.
where ( active == null || p.active == active )
EDIT
The rest of the where clause looks funky too... why is it not just doing
&& p.sub_unit.sub_unit_name == subgroup
or
&& subgroup.Contains(p.sub_unit.sub_unit_name)
?
That is some pretty heavy abuse of the ternary operator.
This expression:
(active == null ? true :
((bool)active ? p.active : !p.active))
Is equivalent to the following logic:
bool result;
if (active == null)
{
result = true;
}
else
{
if ((bool)active)
{
result = p.active;
}
else
{
result = !p.active;
}
}
result &= ...
Think carefully about what this is doing:
If active is null, you're fine, it skips to the next condition.
If active is true, result is true at the end of the conditional.
If active is false, result is false at the end of the conditional.
In the last case, the query can never return any rows!
#Tanzelax has already supplied a simple rewrite. The main idea is that you want to compare p.active to active, not actually evaluate the condition as p.active.
This is probably caused by a null value in one you the columns you have declared as non-nullable. LINQ2SQL makes all columns non-nullable by default. Go back to the designer and change the fields to allow values to be null. Unfortunately this feature is By Design (see connect.microsoft.com link below.)
(linq) incorrect sql generated for row.column == localVar when localVar is null (should be "is null" check)

Resources