Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with join fetch in library #58

Closed
ThienPhuc92 opened this issue Jul 4, 2017 · 1 comment
Closed

Problem with join fetch in library #58

ThienPhuc92 opened this issue Jul 4, 2017 · 1 comment
Milestone

Comments

@ThienPhuc92
Copy link

ThienPhuc92 commented Jul 4, 2017

Hi Darrachequese,

The first, my english is not very well, so maybe some thing i explain about your problem will make you confusing. I'm sorry about that.

I had use your library, but i think your library has some problem.

Your code:

// add JOIN FETCH when necessary
      for (Column column : input.getColumns()) {
        boolean isJoinable =
            column.getSearchable() && column.getData().contains(ATTRIBUTE_SEPARATOR);
        if (!isJoinable) {
          continue;
        }
        String[] values = column.getData().split(ESCAPED_ATTRIBUTE_SEPARATOR);
        PersistentAttributeType type =
            root.getModel().getAttribute(values[0]).getPersistentAttributeType();
        if (type != PersistentAttributeType.ONE_TO_ONE
            && type != PersistentAttributeType.MANY_TO_ONE) {
          continue;
        }
        Fetch<?, ?> fetch = null;
        for (int i = 0; i < values.length - 1; i++) {
          fetch = (fetch == null ? root : fetch).fetch(values[i], JoinType.LEFT);
        }
      }
  • Each column, you will join fetch table. But if column in a same table, it will make very much join fetch query. This is very bad performance.
  • You cannot add a right predicate in some case:
    Example:
    You join fetch 2 table: A, B, then you want to find all result with predicate p1, and predicate p2 on table B.
    your query will be -> SELECT * FROM A a1 JOIN FETCH a1.b b1 JOIN FETCH a1.b b2 WHERE (b1 has p1) AND (b2 has p2).

Right query: SELECT * FROM A a1 JOIN FETCH a1.b b1 WHERE (b1 has p1) AND (b1 has p2)

I resolved this by i convert all column into a tree. A tree will ensure no column duplicate. So i can make right query. But my code is not clean. I wish you improve your library. Some of my code. Hope you consider it to me

@Override
	public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		List<Predicate> predicates = new ArrayList<Predicate>();

		TreeDataTable tree = convertToTree(input.getColumns(), input.getOrder().get(0));

		boolean isCountQuery = query.getResultType() == Long.class;
		if (isCountQuery) {
			predicates.add(cb.and(joinTree(root, cb, tree).toArray(new Predicate[] {})));
		} else {
			predicates.add(cb.and(fetchTree(root, query, cb, tree).toArray(new Predicate[] {})));
		}
		
		if(!subSpecs.isEmpty()) {			
			for(Specification<T> subSpec : subSpecs) {
				predicates.add(cb.and(subSpec.toPredicate(root, query, cb)));
			}
		}

		query.distinct(true);

		return cb.and(predicates.toArray(new Predicate[] {}));
	}


public List<Predicate> fetchTree(From<?, ?> from, CriteriaQuery<?> query, CriteriaBuilder builder,
			TreeDataTable tree) {
		List<Predicate> predicates = new ArrayList<Predicate>(0);

		for (TreeDataTable treeChild : tree.getSubTrees()) {
			boolean isHasChild = treeChild.isHasChild();

			boolean isColumnOrderable = (StringUtils.hasText(treeChild.getHead().getDir()) && !isHasChild);

			String treeName = treeChild.getHead().getName();
			JoinType treeJoinType = treeChild.getHead().getJoinType();
			Class classType = treeChild.getHead().getClassType();
			HashMap<String, String> expressions = treeChild.getHead().getExpression();

			if (isHasChild) {
				Fetch<?, ?> subFetch = from.fetch(treeName, treeJoinType);
				predicates.addAll(fetchTree((From<?, ?>) subFetch, query, builder, treeChild));
			} else {
				predicates.addAll(getPredicates(from, builder, treeName, classType, expressions));

				if (isColumnOrderable) {
					if (treeChild.getHead().getDir().equalsIgnoreCase("asc")) {
						query.orderBy(builder.asc(from.get(treeName)));
					} else {
						query.orderBy(builder.desc(from.get(treeName)));
					}
				}
			}
		}

		return predicates;
	}

Edit: code style

@ThienPhuc92 ThienPhuc92 changed the title Search with multi column Problem with join fetch in library Jul 4, 2017
@darrachequesne
Copy link
Owner

Hi, sorry for the delay!

It seems you're absolutely right, that's something we should fix. Could you provide the code of the convertToTree method?

darrachequesne added a commit that referenced this issue Dec 4, 2017
Previously, a @onetomany relationship could trigger multiple join fetch. Now, there is a maximum of
two 'LEFT JOIN' clauses, one for filtering and one for fetching.

This was made possible by converting the input to a tree. Example:

- name
- company.id
- company.name
- company.description
- company.ceo.name
- company.ceo.age

Tree:

- name
- company
--- name
--- description
--- ceo
----- name
----- age

Closes #58
darrachequesne added a commit that referenced this issue Dec 5, 2017
Previously, a @onetomany relationship could trigger multiple join fetch. Now, there is a maximum of
two 'LEFT JOIN' clauses, one for filtering and one for fetching.

This was made possible by converting the input to a tree. Example:

- name
- company.id
- company.name
- company.description
- company.ceo.name
- company.ceo.age

Tree:

- name
- company
--- name
--- description
--- ceo
----- name
----- age

Closes #58
darrachequesne added a commit that referenced this issue Dec 10, 2017
Previously, a @onetomany relationship could trigger multiple join fetch. Now, there is a maximum of
two 'LEFT JOIN' clauses, one for filtering and one for fetching.

This was made possible by converting the input to a tree. Example:

- name
- company.id
- company.name
- company.description
- company.ceo.name
- company.ceo.age

Tree:

- name
- company
--- name
--- description
--- ceo
----- name
----- age

Closes #58
darrachequesne added a commit that referenced this issue Dec 10, 2017
Previously, a @onetomany relationship could trigger multiple join fetch. Now, there is a maximum of
two 'LEFT JOIN' clauses, one for filtering and one for fetching.

This was made possible by converting the input to a tree. Example:

- name
- company.id
- company.name
- company.description
- company.ceo.name
- company.ceo.age

Tree:

- name
- company
--- name
--- description
--- ceo
----- name
----- age

Closes #58
@darrachequesne darrachequesne added this to the 4.2 milestone Dec 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants