如何在递归实体中找到对象?

时间:2019-03-26 10:19:16

标签: java hibernate jpa recursion

我有以下情况。

对象A有一个递归的对象B,如果它包含任何对象B,我想找到对象A

public class ObjectA {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    @Column(name = "type", nullable = false, insertable = true, updatable 
    = false, length = 8)
    private TypeEnum type;

    @Column(name = "code", nullable = false, insertable = true, updatable 
    = false, length = 20)
    private String code;

    @OneToOne(cascade = { CascadeType.PERSIST }, fetch = FetchType.EAGER)
    @JoinColumn(name = "node_id", unique = false, nullable = false)
    private ObjectB node;

     //GETTERS AND SETTERS
}

public class ObjectB {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    @Column(name = "type", nullable = false, insertable = true, updatable 
    = false, length = 8)
    private TypeBEnum type;

    @Column(name = "code", nullable = false, insertable = true, updatable 
    = false, length = 20)
    private String code;

    @OneToOne(cascade = { CascadeType.PERSIST }, fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private ObjectB parent;

    @OneToOne(cascade = { CascadeType.PERSIST }, mappedBy = "parent")
    private ObjectB children;

//GETTERS AND SETTERS
}

所以我有这个对象:

ObjectA: {
    type: 'MyType',
    code: 'XXX',
    node: {
       type : 'FIRST',
       code : 'First Node',
       children : {
           type : 'SECOND',
           code : 'Second Node',
           children : {
               type : 'THIRD',
               code : 'Third Node'
           } 
       }
   }
}

我的存储库:

public interface ObjectADao
        extends JpaRepository<ObjectA, Long>, 
JpaSpecificationExecutor<ObjectA> {
@Query("SELECT c FROM ObjectA c "
        + "INNER JOIN ObjectB n "
        + "ON c.node.id = n.id "
        + "WHERE c.type = :type AND c.code = :code "
        + "AND c.node = :node")
    Optional<ChainEntity> findBy(@Param("type") TypeEnum type, 
@Param("code") String code, @Param("node") ObjectBEntity node);

}

在这种情况下,如果我通过完整的ObjectB,我可以获得ObjectA。

我需要的是它更加灵活,并根据对象A的类型和代码以及一个或两个节点来获取所有对象

例如,对象A具有所请求的类型和代码,并且具有类型为“ THIRD”且代码为“第三节点”的节点。

或 objectA具有请求的类型和代码,其节点类型为“ THIRD”,代码为“第三节点”,节点类型为“ SECOND”,代码为“第二节点”。

Thx

2 个答案:

答案 0 :(得分:0)

如果我正确理解了您的问题,那么这是解决问题的一种方法。

我将children字段替换为child,由于关系是OneToOne,因此更正确。

无论如何,这是一个SQL查询,允许您执行类似的操作(将其转换为JPA不会太困难):

SELECT parent.*, child1.*, child2.* 
FROM ObjectA parent
INNER JOIN ObjectB child1
ON parent.node_id = child1.id
INNER JOIN ObjectB child2
ON child1.child_id = child2.id
WHERE parent.code = "XXX"
AND parent.type = "MyType"
AND child1.code = "Third Node"
AND child1.type = "THIRD"
AND child2.code = "Second Node"
AND child2.type = "SECOND";

但是,这样做将无法查询具有任意深度的层次结构,如果需要,您将必须为每个深度定义一个查询。为了使用此类数据结构获得最大的灵活性和性能,您应该考虑使用诸如Neo4JOrientDb之类的图形数据库。

更新:

我确定MySQL不支持此功能,因此我从中得出一点,MariaDB也不支持。但是,似乎Maria 10.2.2+确实支持WITH RECURSIVE,而您说找不到。那么,您使用的是旧版本吗? https://mariadb.com/kb/en/library/recursive-common-table-expressions-overview/

答案 1 :(得分:0)

我使用了WITH RECURSIVE的解决方案,虽然我感到不舒服,但我发现它没有更整洁的方式。

我必须使代码成为本机sql,因为JPA无法识别或找不到执行该方法的方法,这取决于数据库的版本,因此,如果数据库版本更改,则必须验证函数的连续性。 / p>

  

我已经使objectA之间的双向关系<->   objectB

@Query(value = "SELECT * FROM object_a AS a WHERE id IN ("
    + " WITH RECURSIVE parents AS ("
    + " SELECT id, code, parent_id, object_a_id"
    + " FROM object_b"
    + " WHERE type = :type AND code = :code"
    + " UNION ALL"
    + " SELECT b.id, b.code, b.parent_id, b.object_a_id"
    + " FROM object_b b, parents p"
    + " WHERE b.id = p.parent_id )"
    + " SELECT object_a_id FROM parents WHERE object_a_id is not null)", nativeQuery = true)
    List<ObjectA> findByTypeAndNode(@Param("type") String type, @Param("code") String code);

我继续接受有关如何使其更清洁的想法。