【问题标题】:Drools + Hibernate: Need to simulate Left Outer Join with OR condition in ruleDrools + Hibernate:需要在规则中使用 OR 条件模拟左外连接
【发布时间】:2015-09-24 12:03:07
【问题描述】:

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

我目前正在使用 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

【问题讨论】:

    标签: java hibernate drools


    【解决方案1】:

    完全没有必要使用“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" 所在的每个关联保险触发。要将其减少为单个激活,请在保险模式前加上 exists(或 not 以获得稍微不同的效果)。

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

    【讨论】:

    • 这适用于状态和保险是一对一关系的情况。我还在处理 Insurance 是来自 Account 的一对多关系的情况,其中 .getInsurance() 在 Hibernate 映射中返回一个 Set 对象。有没有办法编写一个规则来检查从 .getInsurance() 返回的所有 Insurance 对象,以查看其中一个是否包含 currentInd == "N")?
    • 这种方式确实存在
    猜你喜欢
    • 2018-01-16
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    相关资源
    最近更新 更多