Как предотвратить загрузку полного дерева базы данных сразу? - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь использовать компонент Tree в библиотеке PrimeFaces.Но из-за большого количества данных мне приходится загружать их лениво.Я следовал туто, чтобы сделать это (http://blog.disy.net/primefaces-lazy-tree/), но для загрузки требуется 15 сек (вместо 23 сек). Я что-то упустил в этом туто или в моем коде? И я не могу этого допустить, потому что 15 сэто слишком долго для пользователей ... Код ниже

public interface TreePodeFindWithParent {

List<VArboParObjectifsParents> findActiviteWithParent(Integer parentId); 

}

Метод в классе отложенной загрузки

public class PodeLazyTreeNode extends DefaultTreeNode
{
...
...
public PodeLazyTreeNode(VArboParObjectifsParents data, TreePodeService service)
{
super(vArboParObjectifsParents.class.getSimpleName(), data, null);
this.service = service;
}

...

private void ensureChildrenFetched() 
{
    if (!childrenFetched)
    {
        childrenFetched = true;
        if ((VArboParObjectifsParents)getData() != null)
        {
            Integer parentId = ((VArboParObjectifsParents)getData()).getIdRoot();

            List<PodeLazyTreeNode> childNodes = service.findActiviteWithParent(parentId).stream().map(item 
                    -> new PodeLazyTreeNode(item, service)).collect(Collectors.toList());

            super.getChildren().addAll(childNodes);
        }

    }
}

Метод в службе

public class TreePodeService implements Serializable, TreePodeWithParent
{
...
...
@Inject
private PodeArboParObjectifsParentsDao podeArboObjParentDao;
...
@Override
public List<VArboParObjectifsParents> findActiviteWithParent(Integer parentId) {
    // TODO Auto-generated method stub
    return podeArboObjParentDao.findByIdParent(parentId);
}

DAO(Запросы выполняются с помощью модуля данных Apache DeltaSpike)

@Repository(forEntity=VArboParObjectifsParents.class)
public interface PodeArboParObjectifsParentsDao extends EntityRepository<VArboParObjectifsParents, Integer>
{
List<VArboParObjectifsParents> findByIdParent(Integer idParent);
List<VArboParObjetcifsParents> findByIdTypeActivite(Integer idType);
}

Вызов метода в представлении

@PostConstruct
public void initView()
{
    initArbo();
}


public void initArbo()
{
    List<VArboParObjectifsParents> vArbos = treePodeService.getPodeArboObjParentDao().findByIdTypeActivite(1);
    this.root = new PodeLazyTreeNode(null, treePodeService);
    for (int i = 0; i < vArbos.size(); i++)
    {
        root.getChildren().add(new PodeLazyTreeNode(vArbos.get(i), treePodeService));
    }
}

UI

<p:tree value="#{testView.root}" var="_node" >
                <p:treeNode type="VArboParObjectifsParents">
                    <h:outputText value="#{_node}"/>
                </p:treeNode>

             </p:tree> 

Спасибо.

1 Ответ

0 голосов
/ 28 сентября 2018

Причина проблемы

Из PrimeFaces Витрина :

Дерево имеет два режима, в режиме клиента все узлы доступны на клиентеside , тогда как в режиме ajax доступны только расширенные узлы.

Это означает, что все узлы дерева загружаются в браузер до того, как дерево становится видимым.Чем больше у вас узлов, тем больше вызовов сервису требуется для загрузки всего дерева.На странице есть также подсказка, которую вы связали :

n + 1 Проблема

Наша реализация до сих пор была оченьпросто.Тем не менее, это делает большой упор на BackendService.Всякий раз, когда узел раскрывается, выполняется вызов BackendService.findWithParent (...) для каждого дочернего элемента расширенного узла.Это называется n + 1-проблема, так как вам нужно n + 1 сервисных вызовов для предоставления расширенного узла.


Решение

Используйте режим дерева AJAXустановив dynamic="true" (и дополнительно cache="false", чтобы всегда перезагружать дочерние узлы) и загрузить / удалить дочерние узлы, вызвав прослушиватель в представлении.

Также, пожалуйста, не указывайте службу черезконструктор.Учебник, который вы нашли, довольно плох, по моему мнению.Внедрить службу в компонент поддержки и загрузить туда данные узла.

Пример:

Facelet (UI)

<p:tree cache="false"
        dynamic="true"
        value="#{testView.root}" var="_node">

  <!--load/update nodes on demand-->
  <p:ajax event="expand"
          listener="#{testView.onNodeExpand}" />
  <p:ajax event="collapse"
          listener="#{testView.onNodeCollapse}" />

  <p:treeNode type="VArboParObjectifsParents">
    <h:outputText value="#{_node}"/>
  </p:treeNode>
</p:tree>

Фасоль (вид)

@Named
@ViewScoped
public TestView implements Serializable {

    @PostConstruct
    public void initView()
    {
        initArbo();
    }


    public void initArbo()
    {
        List<VArboParObjectifsParents> vArbos = treePodeService.getPodeArboObjParentDao().findByIdTypeActivite(1);
        this.root = new PodeLazyTreeNode(null);
        for (int i = 0; i < vArbos.size(); i++)
        {
            PodeLazyTreeNode childNode = new PodeLazyTreeNode(vArbos.get(i), this.root);
            addDummyTreeNode(childNode);
        }
    }

    public void onNodeExpand(NodeExpandEvent event) {
        final TreeNode expandedTreeNode = event.getTreeNode();

        // load child data from service
        // ...
        if (/* child data available */) {
            // create child tree nodes with dummy tree node
            // ...
            expandedTreeNode.setExpanded(true);
        } else {
            // remove dummy tree nod to mark as leaf
            // ...
            expandedTreeNode.setExpanded(false);
        }
    }

    public void onNodeCollapse(NodeCollapseEvent event) {
        final TreeNode collapsedTreeNode = event.getTreeNode();

        // remove child nodes and add dummy tree node
        // ...

        collapsedTreeNode.setExpanded(false);
    }

    /**
     * Adds a dummy {@link TreeNode} to the specified parent node. The dummy is
     * used to prevent nodes with child nodes from being rendered as leaf nodes
     * until they are expanded. The dummy will be removed when the parent node
     * is expanded the first time.
     *
     * @param parentTreeNode
     */
    private void addDummyTreeNode(TreeNode parentTreeNode) {
        final TreeNode dummyNode = new DefaultTreeNode("Loading...",
                parentTreeNode);
    }

}
...