Drools + Hibernate:需要在规则中使用OR条件模拟Left Outer Join

时间:2015-09-23 15:11:51

标签: java hibernate drools

使用以下规则,我尝试使用具有OR逻辑条件的规则匹配帐户。在这种情况下,我有一个帐户表和这些帐户的保险记录表。并非所有帐户都有保险记录。存在Hibernate DAO对象,并且存在从Account到Insurance的关联。我没有观察到这条规则的预期行为。在这种情况下,我希望帐户1,2,3和4符合此规则,因为规则应匹配任何状态为"非活动"或任何保险CURRENT_IND值为' N'的帐户。但是,只有帐户2和4符合规则。只有具有保险记录的帐户才会匹配该规则。我希望所有帐户记录的状态='无效',无论其保险记录是否存在。

我目前正在使用Drools 5.6.10.FINAL和Hibernate 3.6.0进行测试。

是否可以使用Hibernate和Drools创建这样的规则?是什么导致规则过滤保险记录'存在?

package com.app.Testing
import com.app.abilities.RuleBuilder.EvalObject;
import com.app.dao.Insurance;
import com.app.dao.Account;

rule "Null Test"
when
 $V1 : Account( )
 $V2 : Insurance( ) from $V1.getInsurance()
 $V3 : EvalObject(
    $V2.getCurrentInd == "N" || 
    $V1.getStatus == "Inactive"
 )
then
  reply.getReplyList().add("Null Test");
end

示例数据:

Account:
ACCT_ID    STATUS
1          Inactive
2          Inactive
3          Inactive
4          Active
5          Active


Insurance:
ID    CURRENT_IND
2     N
4     N
5     Y

1 个答案:

答案 0 :(得分:2)

使用“from”访问某个事实的现成字段是完全没必要的 - 您可以通过绑定变量或getter访问。这就是导致问题的原因:无法将“null”值“转换”为模式,因此任何具有insurance == null的Account都将阻止进一步的评估。

此外,我发现使用完全事实(EvalObject)来编写布尔值而非巴洛克式。一个简单的eval应该可以很好地完成,即使你必须使用那种糟糕的Java语法。

总而言之,以下规则会触发您的所有四个帐户:

rule "Better Test"
when
    $V1: Account( $sta: status, $ins: insurance )
    eval( $sta.equals( "Inactive" ) ||
          $ins != null && $ins.getCurrentInd().equals( "N" ) )
then
    System.out.println("Better Test " + $V1.getId() );
end

逻辑当然是一件非常精彩的事情,如果应用得很好,它将跟随皮带的拉扯。因此,您还可以使用一些规则:

rule "Third Test A"
when
    $V1: Account( $sta: status == "Inactive" )
then
    System.out.println("Third Test A " + $V1.getId() );
end
rule "Third Test B"
when
    $V1: Account( $sta: status == "Active" )
    Insurance( currentInd == "N" ) from $V1.getInsurance()
then
    System.out.println("Third Test B " + $V1.getId() );
end
“啊,”我听到你说,“他让我使用两个规则来解决一个问题吗?复制RHS代码?Phooey!”

不,不是我:这只是决赛的桥梁。怎么样:

rule "Fourth Test"
when
    $V1: Account( $sta: status == "Inactive" )
    or
    ($V1: Account( $sta: status == "Active" )
    and
    Insurance( currentInd == "N" ) from $V1.getInsurance()
    )
then
    System.out.println("Fourth Test " + $V1.getId() );
end

修改如果某个帐户可能与任意数量的保险事实相关联(即getInsurance返回Collection<Insurance>),则最后三个规则的工作状况一样好。但是,他们将为currentInd == "N"的每个相关保险开火。要将此减少为单次激活,请使用存在(或)为保险模式添加前缀,以获得稍微不同的效果。

总是值得考虑输入依赖对象(保险)作为事实。此外,从孩子到父母(帐户)的链接可以改善问题。