Hello, all,
I've designed a simple generic problem to demonstrate our issue. (We
are building a system having difficulty designing fact classes that do
not produce infinite loops and wanted input/discussion from Drools
users.)
I'd like to assert Mothers and Fathers to an engine and then ensure
that each mother and father produces exactly one child, where the
child has the father's first and last name and the mother's middle
name. Of course, I could achieve this in one rule, but I like to break
out the rules so that as my requirements change I can change a single
rule (for example, suppose the requirement changes such that the child
should not get its middle name set to its mother's but its mother's
last name).
My object model is Mother, Father, and Child, but the following rules
produce an infinite execution loop in the rules engine.
I know why this is; it is because i have to update($child) whenever I
modify it--even if I modify a single property on the child. All other
rules that use the child in their LHS will re-fire thinking that the
entire fact has changed. The way to fix this is to not use the Mother,
Father, and Child objects as mutable facts but introduce other Classes
that represent the *properties* first, middle, and last name... in
this case I would produce fact "new MiddleName( $child, "Sue" )", for
example. But this results in less-readable rules.
Why can't Drools allow us to indicate property-updates (and track
facts at the property-level, not at the class level)? Or is there
another suggestion to offer?
Here are the rules:
=====
rule "Every mother and father produce a child"
no-loop
when
$mother : Mother( )
$father : Father( )
eval( $mother.getPartner() == $father )
then
Child child = new Child($mother.getId() + "-" + $father.getId());
child.setMother($mother);
child.setFather($father);
insertLogical( child );
end
rule "Every child gets his/her father's first and last name"
no-loop
when
$father : Father( )
$child : Child( father == $father )
then
$child.setFirst($father.getFirst());
$child.setLast($father.getLast());
update($child);
end
rule "Every child gets his/her mother's middle name"
no-loop
when
$mother : Mother( )
$child : Child( mother == $mother )
then
$child.setMiddle($mother.getMiddle());
update($child);
end
=====
Show replies by date
Here's how I'd address this issue. I haven't compiled or run this but I
hope it communicates the idea.
rule "Every mother and father produce a child"
no-loop
when
$mother : Mother( )
$father : Father( )
not Child( mother = $mother, father = $father )
then
Child child = new Child($mother.getId() + "-" + $father.getId());
child.setMother($mother);
child.setFather($father);
insertLogical( child );
end
rule "Every child gets his/her father's first and last name"
no-loop
when
$father : Father( $first: first, $last: last )
$child : Child( father == $father,
first != $first,
last != last )
then
$child.setFirst($first);
$child.setLast($last);
update($child);
end
rule "Every child gets his/her mother's middle name"
no-loop
when
$mother : Mother( $middle: middle )
$child : Child( mother == $mother,
middle != middle )
then
$child.setMiddle($middle);
update($child);
end