Missing join clause on generated SQL for a select of a subclass property

Description

Hibernate isn't generating the join clause of a subclass when I try to select a subclass property.

Class hierarchy:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class A
{
private String a;
}

@Entity
public class B extends A
{
private String b;
}

With the following HQL it generates a SQL with a unknown alias name "a0_1_":
HQL: SELECT a.b FROM com.nm.test.A a
SQL: select a0_1_.b as col_0_0_ from A a0_

What raises the error:
ERROR JDBCExceptionReporter:72 - The multi-part identifier "a0_1_.b" could not be bound.

Looks like it is generating the alias for the select clause, but it isn't creating the alias on the from clause.

If I add the full object a to the select clause, it works (but it is just a workaround since it will degrade performance):

HQL: SELECT a, a.b FROM com.nm.test.A a
SQL: select a0_.id as col_0_0_, a0_1_.b as col_1_0_, a0_.id as id0_, a0_.a as a0_, a0_1_.b as b1_, case when a0_1_.id is not null then 1 when a0_.id is not null then 0 end as clazz_ from A a0_ left outer join B a0_1_ on a0_.id=a0_1_.id

Attachments

1
  • 07 Apr 2006, 05:12 PM

Activity

Show:

William Monti April 17, 2006 at 10:33 PM

The problem occurs because hibernate doesn't include the join subclasses when properties are selected in the select clause. The method FromElement.setIncludeSubclasses(true); isn't called on that situation.

I've made a workaround on DotNode.getColumns() that checks if one of the columns returned to build the select fragment is using a subclass property, if so, it calls setIncludeSubclasses(true);

The new method version is the following:

/** Pattern to detect if a column name is a property subclass, i.e., if it has two or more '_' followed by a dot and some text */
private final static Pattern SUBCLASS_PATTERN = Pattern.compile("(.)_(.)_
.(.)*");

private String[] getColumns() throws QueryException
{
if (columns == null) {
// Use the table fromElement and the property name to get the array
// of column names.
String tableAlias = getLhs().getFromElement().getTableAlias();
columns = getFromElement().toColumns(tableAlias, propertyPath, false);

/* PATCH start */
// Check if one of the columns returned represents a subclass property, if so, call setIncludeSubclasses(true) on FromElement
final int count = columns.length;
for (int i = 0; i < count; i++) {
if (SUBCLASS_PATTERN.matcher(columns[i]).matches()) {
getFromElement().setIncludeSubclasses(true);
break;
}
}
/* PATCH end */
}
return columns;
}

That generates the correct SQL for the first example:
HQL: SELECT a.b FROM com.nm.test.A a
SQL: select a0_1_.b as col_0_0_ from A a0_ left outer join B a0_1_ on a0_.id=a0_1_.id

And doesn't mess with select of properties of the from class:
HQL: SELECT a.a FROM com.nm.test.A a
SQL: select a0_.a as col_0_0_ from A a0_

But it isn't the best way to correct the problem, since it will generate joins for every subclass of the from class, what will seriously degrade performance in a more complex class hierarchy.

Today the column names used by hibernate to create the SQL query are returned as an array of Strings by PropertyMapping.toColumns(), that calls AbstractEntityPersister.getSubclassPropertyTableNumber() in order to generate the column texts of subclass properties. But the problem is that it doesn't track those property table numbers used on column texts, generating an invalid SQL with a missing table alias (the table alias is generated on the select clause, but not on the from clause).

My proposal is to change PropertyMapping.toColumns() to return an array of a new class that has information of the column text (actual information returned as String) and of the subclasses referred by that column and then change FromElement to track those subclasses in order to generate the from clause with just the required subclass joins, instead of using setIncludeSubClasses(true) that will generate joins for every subclass.

Since I am not an expert at hibernate internals and my proposal involves a lot of changes (there are many classes that implements PropertyMapping), I want to check with the hibernate team if that is a good solution or not.

Duplicate

Details

Assignee

Reporter

Components

Affects versions

Priority

Created April 7, 2006 at 5:12 PM
Updated November 16, 2006 at 6:05 PM
Resolved November 16, 2006 at 6:05 PM

Flag notifications