@Override public void appendTo(HqlQuery query, HqlQueryBuilderParams params) { HqlQueryValueImpl from = new HqlQueryValueImpl(); from.appendHql(helper.getEntityName(root.getPropertyType())); from.appendHql(" ").append(root.getAlias()); for (TypeSafeQueryJoin<?> join : joins) { TypeSafeQueryProxyData data = join.getData(); if (data.getProxy() == null) { throw new IllegalStateException( format("Data [%s] was added as a join, but does not have a proxy.", data)); } JoinType effectiveJoinType = data.getEffectiveJoinType(); if (effectiveJoinType == null) { throw new IllegalArgumentException( "The getter for [" + data.getProxy() + "] was called, " + "but it was not passed to query.join(object, jointype)."); } if (data.getPropertyPath() == null) { appendClassJoin(from, join, params); } else if (effectiveJoinType != JoinType.None) { if (isChildOfClassJoin(join)) { appendPropertyAsClassJoin(from, join, params); } else { appendPropertyJoin(from, join, params); } } } query.appendFrom(from.getHql()); query.addParams(from.getParams()); }
/** * Adds additional restrictions to the existing from statement, continuing with <code>glue</code> * if such restrictions exist. */ private boolean appendAdditionalRestrictions( HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, String glue, HqlQueryBuilderParams params) { HqlQueryValue hqlQueryValue = join.getRestrictions().toHqlQueryValue(params); String withHql = hqlQueryValue.getHql(); if (withHql.length() > 0) { from.appendHql(glue).append(withHql); from.addParams(hqlQueryValue.getParams()); return true; } return false; }
/** * Check if one of the parents in the hierarchy for this join is a propertyPath-less parent before * reaching the root. * * <p>In Hibernate 5.1.0, the hql is not properly converted to sql when such a case exists. */ private boolean isChildOfClassJoin(TypeSafeQueryJoin<?> join) { TypeSafeQueryProxyData data = join.getData(); while (data.getParent() != null) { TypeSafeQueryProxyData parent = data.getParent(); if (parent.getParent() == null) { // root found, no class join in between return false; } else if (parent.getPropertyPath() == null) { // property path -less parent found before root // this is a class join return true; } data = parent; } return false; }
/** * Create a join on for a property joined entity which is the child of a class joined entity. This * is a work around because hibernate doesn't properly convert the hql to sql in this case. (the * hql looks fine, but the sql throws an SqlGrammarException and the sql property join is missing) */ private void appendPropertyAsClassJoin( HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, HqlQueryBuilderParams params) { // example: 'left join Product hobj1 on ...' TypeSafeQueryProxyData data = join.getData(); String alias = data.getAlias(); StringBuilder joinSB = new StringBuilder(" ") .append(getJoinTypeString(data.getEffectiveJoinType())) .append(" ") .append(helper.getEntityName(data.getPropertyType())) .append(" ") .append(alias) .append(" on "); if (data.getProxyType().isCollection()) { String parentId = data.getParent().getIdentifierPath(); // parent.parentIdentifier = child.parentPath.parentIdentifier String mappedByProperty = helper.getMappedByProperty(data); joinSB .append(data.getParent().getAlias()) .append(".") .append(parentId) .append(" = ") .append(alias) .append(".") .append(mappedByProperty) .append(".") .append(parentId); } else { String childId = data.getIdentifierPath(); // child.childIdentifier = parent.childPath.childIdentifier joinSB .append(alias) .append(".") .append(childId) .append(" = ") .append(data.getParent().getAlias()) .append(".") .append(data.getPropertyPath()) .append(".") .append(childId); } from.appendHql(joinSB.toString()); // append additional "with" restrictions if such exist (continue after identity restriction): appendAdditionalRestrictions(from, join, " and ", params); }
private void appendPropertyJoin( HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, HqlQueryBuilderParams params) { TypeSafeQueryProxyData data = join.getData(); // example: 'left join fetch' 'hobj1'.'propertyPath' 'hobj2' from.appendHql( new StringBuilder(" ") .append(getJoinTypeString(data.getEffectiveJoinType())) .append(" ") .append(data.getParent().getAlias()) .append(".") .append(data.getPropertyPath()) .append(" ") .append(data.getAlias()) .toString()); // append additional "with" restrictions if such exist: appendAdditionalRestrictions(from, join, " with ", params); }
/** Add class join while validating an on case was specified. */ private void appendClassJoin( HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, HqlQueryBuilderParams params) { // example: 'left join Product hobj1 on ...' TypeSafeQueryProxyData data = join.getData(); from.appendHql( new StringBuilder(" ") .append(getJoinTypeString(data.getEffectiveJoinType())) .append(" ") .append(helper.getEntityName(data.getPropertyType())) .append(" ") .append(data.getAlias()) .toString()); // add the user specified on restrictions, there should at least but some restriction: if (!appendAdditionalRestrictions(from, join, " on ", params)) { if (params.isBuildingForDisplay()) { from.appendHql(" on ????? "); } else { throw new IllegalStateException( String.format( "Class join without on restriction exists for class [%s]", data.getPropertyType())); } } }