[hibernate-commits] Hibernate SVN: r21135 - in annotations/branches/v3_4_0_GA_CP/src: test/java/org/hibernate/test and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Sat Jun 29 13:52:40 EDT 2013


Author: brmeyer
Date: 2013-06-29 13:52:40 -0400 (Sat, 29 Jun 2013)
New Revision: 21135

Added:
   annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/
   annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/
   annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/DestinationEntity.java
   annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/FromEntity.java
   annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/NamedNativeQueryTest.java
Modified:
   annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
Log:
HHH-4412 JBPAPP-10799 bulk update with native sql queries

Modified: annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java	2013-06-29 16:15:18 UTC (rev 21134)
+++ annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java	2013-06-29 17:52:40 UTC (rev 21135)
@@ -48,7 +48,7 @@
 				queryName,
 				getBoolean( queryName, "org.hibernate.cacheable", hints ),
 				getString( queryName, "org.hibernate.cacheRegion", hints ),
-				getInteger( queryName, "org.hibernate.timeout", hints ),
+				getTimeout( queryName, hints ),
 				getInteger( queryName, "org.hibernate.fetchSize", hints ),
 				getFlushMode( queryName, hints ),
 				getCacheMode( queryName, hints ),
@@ -84,7 +84,7 @@
 					null,
 					getBoolean( queryName, "org.hibernate.cacheable", hints ),
 					getString( queryName, "org.hibernate.cacheRegion", hints ),
-					getInteger( queryName, "org.hibernate.timeout", hints ),
+					getTimeout( queryName, hints ),
 					getInteger( queryName, "org.hibernate.fetchSize", hints ),
 					getFlushMode( queryName, hints ),
 					getCacheMode( queryName, hints ),
@@ -105,7 +105,7 @@
 					null,
 					getBoolean( queryName, "org.hibernate.cacheable", hints ),
 					getString( queryName, "org.hibernate.cacheRegion", hints ),
-					getInteger( queryName, "org.hibernate.timeout", hints ),
+					getTimeout( queryName, hints ),
 					getInteger( queryName, "org.hibernate.fetchSize", hints ),
 					getFlushMode( queryName, hints ),
 					getCacheMode( queryName, hints ),
@@ -116,7 +116,21 @@
 			);
 		}
 		else {
-			throw new NotYetImplementedException( "Pure native scalar queries are not yet supported" );
+			query = new NamedSQLQueryDefinition(
+					queryName,
+					new NativeSQLQueryReturn[0],
+					null,
+					getBoolean( queryName, "org.hibernate.cacheable", hints ),
+					getString( queryName, "org.hibernate.cacheRegion", hints ),
+					getTimeout( queryName, hints ),
+					getInteger( queryName, "org.hibernate.fetchSize", hints ),
+					getFlushMode( queryName, hints ),
+					getCacheMode( queryName, hints ),
+					getBoolean( queryName, "org.hibernate.readOnly", hints ),
+					getString( queryName, "org.hibernate.comment", hints ),
+					null,
+					getBoolean( queryName, "org.hibernate.callable", hints )
+			);
 		}
 		if ( isDefault ) {
 			mappings.addDefaultSQLQuery( queryAnn.name(), query );
@@ -386,4 +400,18 @@
 		}
 		return null;
 	}
+
+	private static Integer getTimeout(String queryName, QueryHint[] hints) {
+		Integer timeout = getInteger(queryName,
+				"javax.persistence.query.timeout", hints);
+
+		if (timeout != null) {
+			// convert milliseconds to seconds
+			timeout = (int) Math.round(timeout.doubleValue() / 1000.0);
+		} else {
+			// timeout is already in seconds
+			timeout = getInteger(queryName, "org.hibernate.timeout", hints);
+		}
+		return timeout;
+	}
 }

Added: annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/DestinationEntity.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/DestinationEntity.java	                        (rev 0)
+++ annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/DestinationEntity.java	2013-06-29 17:52:40 UTC (rev 21135)
@@ -0,0 +1,99 @@
+/* 
+ * Hibernate, Relational Persistence for Idiomatic Java
+ * 
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @authors tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+package org.hibernate.test.jpa.ql;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedNativeQueries;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.Table;
+
+/**
+ * @author Janario Oliveira
+ */
+ at Entity
+ at Table(name = "destination_entity")
+ at NamedNativeQueries({
+		@NamedNativeQuery(name = "DestinationEntity.insertSelect", query = "insert into destination_entity(id, from_id, fullNameFrom) "
+				+ " select fe.id, fe.id, fe.name||fe.lastName from from_entity fe where fe.id in (:ids)"),
+		@NamedNativeQuery(name = "DestinationEntity.insert", query = "insert into destination_entity(id, from_id, fullNameFrom) "
+				+ "values (:generatedId, :fromId, :fullName)"),
+		@NamedNativeQuery(name = "DestinationEntity.update", query = "update destination_entity set from_id=:idFrom, fullNameFrom=:fullName"
+				+ " where id in (:ids)"),
+		@NamedNativeQuery(name = "DestinationEntity.delete", query = "delete from destination_entity where id in (:ids)"),
+		@NamedNativeQuery(name = "DestinationEntity.selectIds", query = "select id, from_id, fullNameFrom from destination_entity where id in (:ids)") })
+public class DestinationEntity {
+
+	@Id
+	@GeneratedValue
+	Integer id;
+	@ManyToOne(optional = false)
+	@JoinColumn(name = "from_id")
+	FromEntity from;
+	@Column(nullable = false)
+	String fullNameFrom;
+
+	public DestinationEntity() {
+	}
+
+	public DestinationEntity(FromEntity from, String fullNameFrom) {
+		this.from = from;
+		this.fullNameFrom = fullNameFrom;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ( ( from == null ) ? 0 : from.hashCode() );
+		result = prime * result + ( ( fullNameFrom == null ) ? 0 : fullNameFrom.hashCode() );
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if ( this == obj )
+			return true;
+		if ( obj == null )
+			return false;
+		if ( getClass() != obj.getClass() )
+			return false;
+		DestinationEntity other = (DestinationEntity) obj;
+		if ( from == null ) {
+			if ( other.from != null )
+				return false;
+		}
+		else if ( !from.equals( other.from ) )
+			return false;
+		if ( fullNameFrom == null ) {
+			if ( other.fullNameFrom != null )
+				return false;
+		}
+		else if ( !fullNameFrom.equals( other.fullNameFrom ) )
+			return false;
+		return true;
+	}
+
+}

Added: annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/FromEntity.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/FromEntity.java	                        (rev 0)
+++ annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/FromEntity.java	2013-06-29 17:52:40 UTC (rev 21135)
@@ -0,0 +1,77 @@
+/* 
+ * Hibernate, Relational Persistence for Idiomatic Java
+ * 
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @authors tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+package org.hibernate.test.jpa.ql;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @author Janario Oliveira
+ */
+ at Entity
+ at Table(name = "from_entity")
+public class FromEntity {
+
+	@Id
+	@GeneratedValue
+	Integer id;
+	@Column(nullable = false)
+	String name;
+	@Column(nullable = false)
+	String lastName;
+
+	public FromEntity() {
+	}
+
+	public FromEntity(String name, String lastName) {
+		this.name = name;
+		this.lastName = lastName;
+	}
+
+	@Override
+	public int hashCode() {
+		int hash = 5;
+		hash = 53 * hash + ( this.name != null ? this.name.hashCode() : 0 );
+		hash = 53 * hash + ( this.lastName != null ? this.lastName.hashCode() : 0 );
+		return hash;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if ( obj == null ) {
+			return false;
+		}
+		if ( getClass() != obj.getClass() ) {
+			return false;
+		}
+		final FromEntity other = (FromEntity) obj;
+		if ( ( this.name == null ) ? ( other.name != null ) : !this.name.equals( other.name ) ) {
+			return false;
+		}
+		if ( ( this.lastName == null ) ? ( other.lastName != null ) : !this.lastName.equals( other.lastName ) ) {
+			return false;
+		}
+		return true;
+	}
+}

Added: annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/NamedNativeQueryTest.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/NamedNativeQueryTest.java	                        (rev 0)
+++ annotations/branches/v3_4_0_GA_CP/src/test/java/org/hibernate/test/jpa/ql/NamedNativeQueryTest.java	2013-06-29 17:52:40 UTC (rev 21135)
@@ -0,0 +1,312 @@
+/* 
+ * Hibernate, Relational Persistence for Idiomatic Java
+ * 
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @authors tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * 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,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ */
+package org.hibernate.test.jpa.ql;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.dialect.MySQLDialect;
+import org.hibernate.dialect.SQLServerDialect;
+import org.hibernate.junit.SkipForDialect;
+import org.hibernate.test.annotations.TestCase;
+
+/**
+ * @author Janario Oliveira
+ */
+public class NamedNativeQueryTest extends TestCase {
+
+	private FromEntity createFrom(String name, String lastName) {
+		Session session = openSession();
+		session.getTransaction().begin();
+		FromEntity fromEntity = new FromEntity( name, lastName );
+		session.save( fromEntity );
+		session.getTransaction().commit();
+		session.close();
+		return fromEntity;
+	}
+
+	private DestinationEntity createDestination(FromEntity fromEntity, String fullName) {
+		final DestinationEntity destinationEntity = new DestinationEntity( fromEntity, fullName );
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		session.save( destinationEntity );
+		session.getTransaction().commit();
+		session.close();
+		return destinationEntity;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<DestinationEntity> findDestinationByIds(List<Integer> ids) {
+		Session session = openSession();
+		List<DestinationEntity> list = session
+				.createQuery( "from DestinationEntity de where de.id in (:ids) order by id" )
+				.setParameterList( "ids", ids ).list();
+		session.close();
+		return list;
+	}
+
+	public void testSingleSelect() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final String fullName = name + " " + lastName;
+		final DestinationEntity destination = createDestination( createFrom( name, lastName ), fullName );
+
+		Session session = openSession();
+		Query select = session.getNamedQuery( "DestinationEntity.selectIds" );
+		select.setParameterList( "ids", Collections.singletonList( destination.id ) );
+		Object[] unique = (Object[]) select.uniqueResult();
+		session.close();
+
+		// Compare the Strings, not the actual IDs.  Can come back as, for ex,
+		// a BigDecimal in Oracle.
+		assertEquals( destination.id + "", unique[0] + "" );
+		assertEquals( destination.from.id + "", unique[1] + "" );
+		assertEquals( destination.fullNameFrom, unique[2] );
+	}
+
+	public void testMultipleSelect() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final List<Integer> ids = new ArrayList<Integer>();
+		final int quantity = 10;
+		final List<DestinationEntity> destinations = new ArrayList<DestinationEntity>();
+		for ( int i = 0; i < quantity; i++ ) {
+			DestinationEntity createDestination = createDestination( createFrom( name + i, lastName + i ), name + i
+					+ lastName + i );
+			ids.add( createDestination.id );
+			destinations.add( createDestination );
+		}
+
+		Session session = openSession();
+		Query select = session.getNamedQuery( "DestinationEntity.selectIds" );
+		select.setParameterList( "ids", ids );
+		List list = select.list();
+		session.close();
+
+		assertEquals( quantity, list.size() );
+		for ( int i = 0; i < list.size(); i++ ) {
+			Object[] object = (Object[]) list.get( i );
+			DestinationEntity destination = destinations.get( i );
+			// Compare the Strings, not the actual IDs.  Can come back as, for ex,
+			// a BigDecimal in Oracle.
+			assertEquals( destination.id + "", object[0] + "" );
+			assertEquals( destination.from.id + "", object[1] + "" );
+			assertEquals( destination.fullNameFrom, object[2] );
+		}
+	}
+
+	public void testInsertSingleValue() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final String fullName = name + " " + lastName;
+		final FromEntity fromEntity = createFrom( name, lastName );
+		final int id = 10000;// id fake
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query insert = session.getNamedQuery( "DestinationEntity.insert" );
+		insert.setParameter( "generatedId", id );
+		insert.setParameter( "fromId", fromEntity.id );
+		insert.setParameter( "fullName", fullName );
+		int executeUpdate = insert.executeUpdate();
+		assertEquals( 1, executeUpdate );
+		session.getTransaction().commit();
+		session.close();
+
+		session = openSession();
+		DestinationEntity get = (DestinationEntity) session.get( DestinationEntity.class, id );
+		session.close();
+
+		assertEquals( fromEntity, get.from );
+		assertEquals( fullName, get.fullNameFrom );
+	}
+
+	@SkipForDialect( value = { MySQLDialect.class, SQLServerDialect.class },
+			comment = "MySQL appears to have trouble with fe.id selected twice in one statement.  SQL Server does not support the || operator.")
+	// TODO: Re-form DestinationEntity.insertSelect to something more supported?
+	public void testInsertMultipleValues() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final List<Integer> ids = new ArrayList<Integer>();
+		final int quantity = 10;
+		final List<FromEntity> froms = new ArrayList<FromEntity>();
+		for ( int i = 0; i < quantity; i++ ) {
+			FromEntity fe = createFrom( name + i, lastName + i );
+			froms.add( fe );
+			ids.add( fe.id );
+		}
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query insertSelect = session.getNamedQuery( "DestinationEntity.insertSelect" );
+		insertSelect.setParameterList( "ids", ids );
+		int executeUpdate = insertSelect.executeUpdate();
+		assertEquals( quantity, executeUpdate );
+
+		session.getTransaction().commit();
+		session.close();
+
+		List<DestinationEntity> list = findDestinationByIds( ids );
+		assertEquals( quantity, list.size() );
+
+		for ( int i = 0; i < quantity; i++ ) {
+			DestinationEntity de = (DestinationEntity) list.get( i );
+			FromEntity from = froms.get( i );
+			assertEquals( from, de.from );
+			assertEquals( from.name + from.lastName, de.fullNameFrom );
+		}
+	}
+
+	public void testUpdateSingleValue() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final String fullName = name + " " + lastName;
+
+		final FromEntity fromEntity = createFrom( name, lastName );
+		final DestinationEntity destinationEntity = createDestination( fromEntity, fullName );
+
+		final String inverseFullName = lastName + " " + name;
+		final FromEntity anotherFrom = createFrom( lastName, name );
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query update = session.getNamedQuery( "DestinationEntity.update" );
+		update.setParameter( "idFrom", anotherFrom.id );
+		update.setParameter( "fullName", inverseFullName );
+		update.setParameterList( "ids", Collections.singletonList( destinationEntity.id ) );
+
+		int executeUpdate = update.executeUpdate();
+		assertEquals( 1, executeUpdate );
+
+		session.getTransaction().commit();
+		session.close();
+
+		session = openSession();
+		DestinationEntity get = (DestinationEntity) session.get( DestinationEntity.class, destinationEntity.id );
+
+		assertEquals( anotherFrom, get.from );
+		assertEquals( inverseFullName, get.fullNameFrom );
+		session.close();
+	}
+
+	public void testUpdateMultipleValues() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final List<Integer> ids = new ArrayList<Integer>();
+		final int quantity = 10;
+		final List<DestinationEntity> destinations = new ArrayList<DestinationEntity>();
+		for ( int i = 0; i < quantity; i++ ) {
+			FromEntity fe = createFrom( name + i, lastName + i );
+			DestinationEntity destination = createDestination( fe, fe.name + fe.lastName );
+			destinations.add( destination );
+			ids.add( destination.id );
+		}
+
+		final String inverseFullName = lastName + " " + name;
+		final FromEntity anotherFrom = createFrom( lastName, name );
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query update = session.getNamedQuery( "DestinationEntity.update" );
+		update.setParameter( "idFrom", anotherFrom.id );
+		update.setParameter( "fullName", inverseFullName );
+		update.setParameterList( "ids", ids );
+
+		int executeUpdate = update.executeUpdate();
+		assertEquals( quantity, executeUpdate );
+
+		session.getTransaction().commit();
+		session.close();
+
+		List<DestinationEntity> list = findDestinationByIds( ids );
+		assertEquals( quantity, list.size() );
+
+		for ( int i = 0; i < quantity; i++ ) {
+			DestinationEntity updated = (DestinationEntity) list.get( i );
+
+			assertEquals( anotherFrom, updated.from );
+			assertEquals( inverseFullName, updated.fullNameFrom );
+		}
+	}
+
+	public void testDeleteSingleValue() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final String fullName = name + " " + lastName;
+
+		final FromEntity fromEntity = createFrom( name, lastName );
+		final DestinationEntity destinationEntity = createDestination( fromEntity, fullName );
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query delete = session.getNamedQuery( "DestinationEntity.delete" );
+		delete.setParameterList( "ids", Collections.singletonList( destinationEntity.id ) );
+
+		int executeUpdate = delete.executeUpdate();
+		assertEquals( 1, executeUpdate );
+
+		session.getTransaction().commit();
+		session.close();
+
+		session = openSession();
+		DestinationEntity get = (DestinationEntity) session.get( DestinationEntity.class, destinationEntity.id );
+		session.close();
+
+		assertNull( get );
+	}
+
+	public void testDeleteMultipleValues() {
+		final String name = "Name";
+		final String lastName = "LastName";
+		final List<Integer> ids = new ArrayList<Integer>();
+		final int quantity = 10;
+		final List<DestinationEntity> destinations = new ArrayList<DestinationEntity>();
+		for ( int i = 0; i < quantity; i++ ) {
+			FromEntity fe = createFrom( name + i, lastName + i );
+			DestinationEntity destination = createDestination( fe, fe.name + fe.lastName );
+			destinations.add( destination );
+			ids.add( destination.id );
+		}
+
+		Session session = openSession();
+		session.getTransaction().begin();
+		Query delete = session.getNamedQuery( "DestinationEntity.delete" );
+		delete.setParameterList( "ids", ids );
+
+		int executeUpdate = delete.executeUpdate();
+		assertEquals( quantity, executeUpdate );
+
+		session.getTransaction().commit();
+		session.close();
+
+		List<DestinationEntity> list = findDestinationByIds( ids );
+		assertTrue( list.isEmpty() );
+	}
+
+	@Override
+	protected Class[] getAnnotatedClasses() {
+		return new Class[] { FromEntity.class, DestinationEntity.class };
+	}
+}



More information about the hibernate-commits mailing list