我有以下情况。
对象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
答案 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";
但是,这样做将无法查询具有任意深度的层次结构,如果需要,您将必须为每个深度定义一个查询。为了使用此类数据结构获得最大的灵活性和性能,您应该考虑使用诸如Neo4J或OrientDb之类的图形数据库。
更新:
我确定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);
我继续接受有关如何使其更清洁的想法。