HHH-5419: Modified HQL rendering of COUNT function so that when a non-distinct entity with an ID is specified as a parameter, it renders a star instead of the ID attribute(s). This allows for greater support across DBs, since some do not support the previous rendering of multiple ID attributes when the ID happens to be a composite ID.

This commit is contained in:
John Verhaeg 2011-10-03 00:41:32 -05:00
parent 9039e4d29e
commit 7d70a909c5
4 changed files with 155 additions and 4 deletions

View File

@ -23,7 +23,9 @@
*/
package org.hibernate.ejb.criteria.expression.function;
import java.io.Serializable;
import java.util.List;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Root;
import org.hibernate.ejb.criteria.CriteriaBuilderImpl;
import org.hibernate.ejb.criteria.CriteriaQueryCompiler;
import org.hibernate.ejb.criteria.expression.LiteralExpression;
@ -92,11 +94,27 @@ public class AggregationFunction<T>
}
@Override
protected void renderArguments(StringBuilder buffer, CriteriaQueryCompiler.RenderingContext renderingContext) {
if ( isDistinct() ) {
buffer.append( "distinct " );
protected void renderArguments( StringBuilder buffer,
CriteriaQueryCompiler.RenderingContext renderingContext ) {
if (isDistinct()) buffer.append("distinct ");
else {
// If function specifies a single non-distinct entity with ID, its alias would normally be rendered, which ends up
// converting to the column(s) associated with the entity's ID in the rendered SQL. However, some DBs don't support
// the multiple columns that would end up here for entities with composite IDs. So, since we modify the query to
// instead specify star since that's functionally equivalent and supported by all DBs.
List<Expression<?>> argExprs = getArgumentExpressions();
if (argExprs.size() == 1) {
Expression argExpr = argExprs.get(0);
if (argExpr instanceof Root<?>) {
Root<?> root = (Root<?>)argExpr;
if (root.getModel().getIdType() != null) {
buffer.append('*');
return;
}
}
}
}
super.renderArguments( buffer, renderingContext );
super.renderArguments(buffer, renderingContext);
}
public boolean isDistinct() {

View File

@ -0,0 +1,48 @@
package org.hibernate.ejb.test;
import java.io.Serializable;
import javax.persistence.Embeddable;
/**
*
*/
@Embeddable
public class CompositeId implements Serializable {
private int id1;
private int id2;
public int getId1() {
return id1;
}
public void setId1( int id1 ) {
this.id1 = id1;
}
public int getId2() {
return id2;
}
public void setId2( int id2 ) {
this.id2 = id2;
}
@Override
public boolean equals( Object obj ) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final CompositeId other = (CompositeId)obj;
if (this.id1 != other.id1) return false;
if (this.id2 != other.id2) return false;
return true;
}
@Override
public int hashCode() {
int hash = 5;
hash = 73 * hash + this.id1;
hash = 73 * hash + this.id2;
return hash;
}
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.ejb.test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.core.Is.is;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.junit.Test;
/**
*
*/
public class CountEntityWithCompositeIdTest extends BaseEntityManagerFunctionalTestCase {
@Test
public void shouldCount() {
EntityManager em = getOrCreateEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<EntityWithCompositeId> r = cq.from(EntityWithCompositeId.class);
cq.multiselect(cb.count(r));
assertThat(em.createQuery(cq).getSingleResult().intValue(), is(0));
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {EntityWithCompositeId.class, CompositeId.class};
}
}

View File

@ -0,0 +1,32 @@
package org.hibernate.ejb.test;
import java.io.Serializable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
/**
*
*/
@Entity
public class EntityWithCompositeId implements Serializable {
@EmbeddedId
private CompositeId id;
private String description;
public CompositeId getId() {
return id;
}
public void setId(CompositeId id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}