Как найти объект в рекурсивной сущности? - PullRequest
0 голосов
/ 26 марта 2019

У меня следующий случай.

У объекта A есть рекурсивный объект B, и я хочу найти объект A, если он содержит какой-либо из объектов B

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);

}

В этом случае я могу получить свой ObjectA, если передам полный ObjectB.

Мне нужно, чтобы он был более гибким, учитывая тип и код объекта A, и один или два узла получают весь объект

Например, objectA имеет запрошенный тип и код и имеетузел, который имеет «THIRD» как тип и «Third Node» как код.

ИЛИ objectA имеет запрошенный тип и код и имеет узел, который имеет «THIRD» как тип и «Third Node»'как код и имеет узел, который имеет' SECOND 'как тип и' Second Node 'как код.

Thx

Ответы [ 2 ]

0 голосов
/ 27 марта 2019

Я применяю решение WITH RECURSIVE, с которым я не чувствую себя комфортно, но я не нахожу более аккуратный способ сделать это.

Мне пришлось сделать код нативный sql, потому что JPA не распознает илиЯ не нашел способ сделать это, и это зависит от версии базы данных, поэтому, если она изменится, мне придется проверить непрерывность функции.

Я установил двустороннюю связь между 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);

Я продолжаю принимать идеи о том, как сделать его чище.

0 голосов
/ 26 марта 2019

Если я правильно понял вашу проблему, то это способ сделать это.

Я заменил поле 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";

Однако при этом вы не сможете запрашивать иерархии с произвольной глубиной, вам придется определять запрос для каждой глубины, если вам нужно. Для достижения максимальной гибкости и производительности с такими структурами данных вам следует рассмотреть возможность использования базы данных графов, такой как Neo4J или OrientDb .

ОБНОВЛЕНИЕ:

Я был уверен, что MySQL не поддерживает это, так что я получил вывод, что MariaDB тоже не поддерживает. Однако, похоже, что Мария 10.2.2+ поддерживает WITH RECURSIVE, и вы сказали, что не можете ее найти. Так вы на старой версии? https://mariadb.com/kb/en/library/recursive-common-table-expressions-overview/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...