过滤器过滤树结构数据

过滤器在对树结构的数据进行过滤时,过滤后的数据如何以树结构的形式进行展示

可以了解一下树形表格,以及孤立记录

使用孤立记录的话,就会搜不到子记录
我想要实现的是,如果搜索的是子记录,则展示一个完整的树

你的意思是如果搜出来没有父记录的子记录,还是需要显示它的父记录展示一棵完整的树?

子记录是不会单独存在的,类似这种
df56c0e64eaf0d07f09d09c67c142e5

这个问题该怎么解决

这个只能自己写过滤了。找到子节点后,要把父节点也加载出来。比方说有个 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);
}

好的,谢谢