过滤器在对树结构的数据进行过滤时,过滤后的数据如何以树结构的形式进行展示
使用孤立记录的话,就会搜不到子记录
我想要实现的是,如果搜索的是子记录,则展示一个完整的树
你的意思是如果搜出来没有父记录的子记录,还是需要显示它的父记录展示一棵完整的树?
子记录是不会单独存在的,类似这种
这个问题该怎么解决
这个只能自己写过滤了。找到子节点后,要把父节点也加载出来。比方说有个 TreeNode
,有id、name、parent 三个属性:
@JmixEntity
@Table(name = "LEOT_TREE_NODE", indexes = {
@Index(name = "IDX_LEOT_TREE_NODE_PARENT", columnList = "PARENT_ID")
})
@Entity(name = "leot_TreeNode")
public class TreeNode {
@JmixGeneratedValue
@Column(name = "ID", nullable = false)
@Id
private UUID id;
@InstanceName
@Column(name = "NAME")
private String name;
@JoinColumn(name = "PARENT_ID")
@ManyToOne(fetch = FetchType.LAZY)
private TreeNode parent;
// ...
}
页面结构:
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://blank2Screen.caption">
<data>
<collection id="treeNodesDc" class="com.company.leot.entity.TreeNode">
<fetchPlan extends="_base"/>
<loader id="treeNodesDl">
<query>
<![CDATA[select e from leot_TreeNode e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<layout>
<hbox>
<textField id="searchField"/>
<button id="searchBtn" caption="Search"/>
</hbox>
<tree dataContainer="treeNodesDc" height="100%" hierarchyProperty="parent" width="100%"/>
</layout>
</window>
TreeNode 搜索服务,这里用到了 EntityManager
执行原生SQL,也可以用 JdbcTemplate:
@Component("leot_TreeNodeService")
public class TreeNodeService {
@PersistenceContext
private EntityManager entityManager;
// 用with recursive 搜索父节点。
private String queryTree = """
WITH RECURSIVE tree_nodes(id,name,parent_id,level) AS (
select id,name,parent_id, 1 as level
from LEOT_TREE_NODE
where name like ?1
union
select n1.id,n1.name,n1.parent_id,tn1.level+1
from LEOT_TREE_NODE n1,tree_nodes tn1 where tn1.parent_id is not null and n1.id = tn1.parent_id
)select distinct (n2.*) from LEOT_TREE_NODE n2,tree_nodes tn2 where n2.id = tn2.id;
""";
public Collection<TreeNode> searchTreeNodes(String key) {
// 结果是 TreeNode 属性的数组。
List<Object[]> list = entityManager.createNativeQuery(queryTree)
.setParameter(1, "%" + key + "%")
.getResultList();
// ID 和节点的map
var map = list.stream().collect(Collectors.toMap(
n -> ((UUID) n[0]).toString(), // key
n -> { //value
var tn = new TreeNode();
tn.setId((UUID) n[0]);
tn.setName((String) n[1]);
if (n[2] != null) {
var parent = new TreeNode();
parent.setId((UUID) n[2]);
// 先用一个parent记录parent的id
tn.setParent(parent);
}
return tn;
}));
map.values().forEach(n -> {
if (n.getParent() != null) {
// 这里重新设置带其他属性的parent
n.setParent(map.get(n.getParent().getId().toString()));
}
});
return map.values();
}
}
页面 Controller:
@Autowired
private CollectionContainer<TreeNode> treeNodesDc;
@Autowired
private TextField<String> searchField;
@Autowired
private TreeNodeService treeNodeService;
@Subscribe("searchBtn")
@Transactional
public void onSearchBtnClick(final Button.ClickEvent event) {
var key = searchField.getValue();
if (StringUtils.isBlank(key)) {
return;
}
var list = treeNodeService.searchTreeNodes(key);
treeNodesDc.setItems(list);
}
好的,谢谢