[hibernate-commits] Hibernate SVN: r18758 - in core/trunk: core/src/main/java/org/hibernate/engine and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Feb 10 02:01:00 EST 2010


Author: gbadner
Date: 2010-02-10 02:00:59 -0500 (Wed, 10 Feb 2010)
New Revision: 18758

Added:
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Course.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/ReadOnlyCriteriaQueryTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Student.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/StudentDTO.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/Criteria.java
   core/trunk/core/src/main/java/org/hibernate/Query.java
   core/trunk/core/src/main/java/org/hibernate/engine/QueryParameters.java
   core/trunk/core/src/main/java/org/hibernate/impl/CriteriaImpl.java
   core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java
Log:
HHH-4578 : Criteria is missing read-only flag

Modified: core/trunk/core/src/main/java/org/hibernate/Criteria.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/Criteria.java	2010-02-10 04:14:39 UTC (rev 18757)
+++ core/trunk/core/src/main/java/org/hibernate/Criteria.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -313,8 +313,62 @@
 	 * @return this (for method chaining)
 	 */
 	public Criteria setFirstResult(int firstResult);
-	
+
 	/**
+	 * Was the read-only/modifiable mode explicitly initialized?
+	 *
+	 * @return true, the read-only/modifiable mode was explicitly initialized; false, otherwise.
+	 *
+	 * @see Criteria#setReadOnly(boolean)
+	 */
+	public boolean isReadOnlyInitialized();
+
+	/**
+	 * Should entities and proxies loaded by this Criteria be put in read-only mode? If the
+	 * read-only/modifiable setting was not initialized, then the default
+	 * read-only/modifiable setting for the persistence context is returned instead.
+	 * @see Criteria#setReadOnly(boolean)
+	 * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly()
+	 *
+	 * The read-only/modifiable setting has no impact on entities/proxies returned by the
+	 * Criteria that existed in the session before the Criteria was executed.
+	 *
+	 * @return true, entities and proxies loaded by the criteria will be put in read-only mode
+	 *         false, entities and proxies loaded by the criteria will be put in modifiable mode
+	 * @throws IllegalStateException if <code>isReadOnlyInitialized()</code> returns <code>false</code>
+	 * and this Criteria is not associated with a session.
+	 * @see Criteria#isReadOnlyInitialized()
+	 */
+	public boolean isReadOnly();
+
+	/**
+	 * Set the read-only/modifiable mode for entities and proxies
+	 * loaded by this Criteria. This setting overrides the default setting
+	 * for the persistence context.
+	 * @see org.hibernate.engine.PersistenceContext#isDefaultReadOnly()
+	 *
+	 * To set the default read-only/modifiable setting used for
+	 * entities and proxies that are loaded into the session:
+	 * @see org.hibernate.engine.PersistenceContext#setDefaultReadOnly(boolean)
+	 * @see org.hibernate.Session#setDefaultReadOnly(boolean)
+	 *
+	 * Read-only entities are not dirty-checked and snapshots of persistent
+	 * state are not maintained. Read-only entities can be modified, but
+	 * changes are not persisted.
+	 *
+	 * When a proxy is initialized, the loaded entity will have the same
+	 * read-only/modifiable setting as the uninitialized
+	 * proxy has, regardless of the session's current setting.
+	 *
+	 * The read-only/modifiable setting has no impact on entities/proxies
+	 * returned by the criteria that existed in the session before the criteria was executed.
+	 *
+	 * @param readOnly true, entities and proxies loaded by the criteria will be put in read-only mode
+	 *                 false, entities and proxies loaded by the criteria will be put in modifiable mode
+	 */
+	public Criteria setReadOnly(boolean readOnly);
+
+	/**
 	 * Set a fetch size for the underlying JDBC query.
 	 *
 	 * @param fetchSize the fetch size

Modified: core/trunk/core/src/main/java/org/hibernate/Query.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/Query.java	2010-02-10 04:14:39 UTC (rev 18757)
+++ core/trunk/core/src/main/java/org/hibernate/Query.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -211,10 +211,9 @@
 	 * The read-only/modifiable setting has no impact on entities/proxies
 	 * returned by the query that existed in the session before the query was executed.
 	 *
-	 * @return true, entities and proxies loaded by the query will be put in read-only mode
-	 *         false, entities and proxies loaded by the query will be put in modifiable mode
+	 * @param readOnly true, entities and proxies loaded by the query will be put in read-only mode
+	 *                 false, entities and proxies loaded by the query will be put in modifiable mode
 	 */
-
 	public Query setReadOnly(boolean readOnly);
 
 	/**

Modified: core/trunk/core/src/main/java/org/hibernate/engine/QueryParameters.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/QueryParameters.java	2010-02-10 04:14:39 UTC (rev 18757)
+++ core/trunk/core/src/main/java/org/hibernate/engine/QueryParameters.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -102,7 +102,7 @@
 	public QueryParameters(
 			final Type[] positionalParameterTypes,
 			final Object[] postionalParameterValues) {
-		this( positionalParameterTypes, postionalParameterValues, null, null, false, null, null, false, null );
+		this( positionalParameterTypes, postionalParameterValues, null, null, false, false, false, null, null, false, null );
 	}
 
 	public QueryParameters(
@@ -138,6 +138,8 @@
 			final Object[] positionalParameterValues,
 			final LockOptions lockOptions,
 			final RowSelection rowSelection,
+			final boolean isReadOnlyInitialized,
+			final boolean readOnly,
 			final boolean cacheable,
 			final String cacheRegion,
 			//final boolean forceCacheRefresh,
@@ -150,8 +152,8 @@
 				null,
 				lockOptions,
 				rowSelection,
-				false,
-				false,
+				isReadOnlyInitialized,
+				readOnly,
 				cacheable,
 				cacheRegion,
 				comment,

Modified: core/trunk/core/src/main/java/org/hibernate/impl/CriteriaImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/impl/CriteriaImpl.java	2010-02-10 04:14:39 UTC (rev 18757)
+++ core/trunk/core/src/main/java/org/hibernate/impl/CriteriaImpl.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -81,6 +81,8 @@
 	private FlushMode sessionFlushMode;
 	private CacheMode sessionCacheMode;
 
+	private Boolean readOnly;
+
 	private ResultTransformer resultTransformer = Criteria.ROOT_ENTITY;
 
 
@@ -272,6 +274,36 @@
 		return this;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isReadOnlyInitialized() {
+		return readOnly != null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean isReadOnly() {
+		if ( ! isReadOnlyInitialized() && getSession() == null ) {
+			throw new IllegalStateException(
+					"cannot determine readOnly/modifiable setting when it is not initialized and is not initialized and getSession() == null"
+			);
+		}
+		return ( isReadOnlyInitialized() ?
+				readOnly.booleanValue() :
+				getSession().getPersistenceContext().isDefaultReadOnly()
+		);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Criteria setReadOnly(boolean readOnly) {
+		this.readOnly = Boolean.valueOf( readOnly );
+		return this;
+	}
+
 	public boolean getCacheable() {
 		return this.cacheable;
 	}
@@ -494,6 +526,19 @@
 			return new Subcriteria( this, associationPath, alias, joinType, withClause );
 		}
 
+		public boolean isReadOnly() {
+			return CriteriaImpl.this.isReadOnly();
+		}
+
+		public boolean isReadOnlyInitialized() {
+			return CriteriaImpl.this.isReadOnlyInitialized();
+		}
+
+		public Criteria setReadOnly(boolean readOnly) {
+			CriteriaImpl.this.setReadOnly( readOnly );
+			return this;
+		}
+
 		public Criteria setCacheable(boolean cacheable) {
 			CriteriaImpl.this.setCacheable(cacheable);
 			return this;

Modified: core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java	2010-02-10 04:14:39 UTC (rev 18757)
+++ core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaQueryTranslator.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -325,6 +325,8 @@
 		        valueArray,
 		        lockOptions,
 		        selection,
+		        rootCriteria.isReadOnlyInitialized(),
+		        ( rootCriteria.isReadOnlyInitialized() ? rootCriteria.isReadOnly() : false ),
 		        rootCriteria.getCacheable(),
 		        rootCriteria.getCacheRegion(),
 		        rootCriteria.getComment(),

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Course.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Course.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Course.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,22 @@
+//$Id: Course.java 5686 2005-02-12 07:27:32Z steveebersole $
+package org.hibernate.test.readonly.criteria;
+
+/**
+ * @author Gavin King
+ */
+public class Course {
+	private String courseCode;
+	private String description;
+	public String getCourseCode() {
+		return courseCode;
+	}
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+}


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Course.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.hbm.xml	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC 
+	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.readonly.criteria">
+	
+	<class name="Course">
+		<id name="courseCode">
+			<generator class="assigned"/>
+		</id>
+		<property name="description"/>
+	</class>
+	
+	<class name="Student">
+		<id name="studentNumber">
+		    <column name="studentId"/>
+			<generator class="assigned"/>
+		</id>
+		<property name="name" not-null="true"/>
+		<set name="enrolments" inverse="true" cascade="delete">
+			<key column="studentId"/>
+			<one-to-many class="Enrolment"/>
+		</set>
+        <many-to-one name="preferredCourse" column="preferredCourseCode"/>
+	</class>
+	
+	<class name="Enrolment">
+		<composite-id>
+			<key-property name="studentNumber">
+				<column name="studentId"/>
+			</key-property>
+			<key-property name="courseCode"/>
+		</composite-id>
+		<many-to-one name="student" insert="false" update="false">
+			<column name="studentId"/>
+		</many-to-one>
+		<many-to-one name="course" insert="false" update="false">
+			<column name="courseCode"/>
+		</many-to-one>
+		<property name="semester" not-null="true"/>
+		<property name="year" not-null="true"/>
+	</class>
+
+</hibernate-mapping>


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.hbm.xml
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,63 @@
+//$Id: Enrolment.java 6970 2005-05-31 20:24:41Z oneovthafew $
+package org.hibernate.test.readonly.criteria;
+
+import java.io.Serializable;
+
+/**
+ * @author Gavin King
+ */
+public class Enrolment implements Serializable {
+	private Student student;
+	private Course course;
+	private long studentNumber;
+	private String courseCode;
+	private short year;
+	private short semester;
+	public String getCourseCode() {
+		return courseCode;
+	}
+	public void setCourseCode(String courseId) {
+		this.courseCode = courseId;
+	}
+	public long getStudentNumber() {
+		return studentNumber;
+	}
+	public void setStudentNumber(long studentId) {
+		this.studentNumber = studentId;
+	}
+	public Course getCourse() {
+		return course;
+	}
+	public void setCourse(Course course) {
+		this.course = course;
+	}
+	public Student getStudent() {
+		return student;
+	}
+	public void setStudent(Student student) {
+		this.student = student;
+	}
+	public short getSemester() {
+		return semester;
+	}
+	public void setSemester(short semester) {
+		this.semester = semester;
+	}
+	public short getYear() {
+		return year;
+	}
+	public void setYear(short year) {
+		this.year = year;
+	}
+	
+	public boolean equals(Object other) {
+		if ( !(other instanceof Enrolment) ) return false;
+		Enrolment that = (Enrolment) other;
+		return studentNumber==that.studentNumber &&
+			courseCode.equals(that.courseCode);
+	}
+	
+	public int hashCode() {
+		return courseCode.hashCode();
+	}
+}


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Enrolment.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/ReadOnlyCriteriaQueryTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/ReadOnlyCriteriaQueryTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/ReadOnlyCriteriaQueryTest.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,1657 @@
+//$Id: CriteriaQueryTest.java 10976 2006-12-12 23:22:26Z steve.ebersole at jboss.com $
+package org.hibernate.test.readonly.criteria;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.Hibernate;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.DetachedCriteria;
+import org.hibernate.criterion.Example;
+import org.hibernate.criterion.MatchMode;
+import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projection;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Property;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.criterion.Subqueries;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.test.hql.Animal;
+import org.hibernate.test.hql.Reptile;
+import org.hibernate.transform.Transformers;
+import org.hibernate.type.Type;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Gail Badner (adapted from org.hibernate.test.criteria.CriteriaQueryTest by Gavin King)
+ */
+public class ReadOnlyCriteriaQueryTest extends FunctionalTestCase {
+	
+	public ReadOnlyCriteriaQueryTest(String str) {
+		super(str);
+	}
+
+	public String[] getMappings() {
+		return new String[] { "readonly/criteria/Enrolment.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
+		cfg.setProperty( Environment.CACHE_REGION_PREFIX, "criteriaquerytest" );
+		cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( ReadOnlyCriteriaQueryTest.class );
+	}
+
+	public void testModifiableSessionDefaultCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Criteria criteria = s.createCriteria( Student.class );
+		assertFalse( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testModifiableSessionReadOnlyCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( true );
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testModifiableSessionModifiableCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		Criteria criteria = s.createCriteria( Student.class );
+		assertFalse( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		criteria.setReadOnly( false );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlySessionDefaultCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.setDefaultReadOnly( true );
+		Criteria criteria = s.createCriteria( Student.class );
+		assertTrue( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertTrue( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertTrue( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlySessionReadOnlyCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.setDefaultReadOnly( true );
+		Criteria criteria = s.createCriteria( Student.class );
+		assertTrue( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		criteria.setReadOnly( true );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertTrue( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertTrue( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlySessionModifiableCriteria() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.setDefaultReadOnly( true );
+		Criteria criteria = s.createCriteria( Student.class );
+		assertTrue( s.isDefaultReadOnly() );
+		assertFalse( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		criteria.setReadOnly( false );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertTrue( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), false);
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertTrue( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlyCriteriaReturnsModifiableExistingEntity() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.get( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( s.isReadOnly( coursePreferred ) );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( true );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( s.isReadOnly( coursePreferred ) );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlyCriteriaReturnsExistingModifiableProxyNotInit() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.load( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( true );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		Hibernate.initialize( coursePreferred );
+		checkProxyReadOnly( s, coursePreferred, false );		
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testReadOnlyCriteriaReturnsExistingModifiableProxyInit() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.load( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		Hibernate.initialize( coursePreferred );
+		checkProxyReadOnly( s, coursePreferred, false );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( true );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertTrue( criteria.isReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertTrue( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testModifiableCriteriaReturnsExistingReadOnlyEntity() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.get( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( s.isReadOnly( coursePreferred ) );
+		s.setReadOnly( coursePreferred, true );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( false );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertTrue( s.isReadOnly( coursePreferred ) );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testModifiableCriteriaReturnsExistingReadOnlyProxyNotInit() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.load( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		s.setReadOnly( coursePreferred, true );
+		checkProxyReadOnly( s, coursePreferred, true );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( false );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, true );
+		Hibernate.initialize( coursePreferred );
+		checkProxyReadOnly( s, coursePreferred, true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+
+	public void testModifiableCriteriaReturnsExistingReadOnlyProxyInit() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist(  coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add( enrolment );
+		s.persist( enrolment );
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		assertFalse( s.isDefaultReadOnly() );
+		coursePreferred = ( Course ) s.load( Course.class, coursePreferred.getCourseCode() );
+		assertFalse( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, false );
+		Hibernate.initialize( coursePreferred );
+		checkProxyReadOnly( s, coursePreferred, false );
+		s.setReadOnly( coursePreferred, true );
+		checkProxyReadOnly( s, coursePreferred, true );
+		Criteria criteria = s.createCriteria( Student.class ).setReadOnly( false );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		gavin = ( Student ) criteria.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( criteria.isReadOnlyInitialized() );
+		assertFalse( criteria.isReadOnly() );
+		assertFalse( s.isReadOnly( gavin ) );
+		assertTrue( Hibernate.isInitialized( coursePreferred ) );
+		checkProxyReadOnly( s, coursePreferred, true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();
+	}
+	
+	public void testScrollCriteria() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		session.persist(course);
+		session.flush();
+		session.clear();
+		ScrollableResults sr = session.createCriteria(Course.class).setReadOnly( true ).scroll();
+		assertTrue( sr.next() );
+		course = (Course) sr.get(0);
+		assertNotNull(course);
+		assertTrue( session.isReadOnly( course ) );
+		sr.close();
+		session.delete(course);
+		
+		t.commit();
+		session.close();
+		
+	}
+	
+	public void testSubselect() {
+
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.persist(course);
+		
+		Course coursePreferred = new Course();
+		coursePreferred.setCourseCode( "JBOSS" );
+		coursePreferred.setDescription( "JBoss" );
+		s.persist( coursePreferred );
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse( coursePreferred );
+		s.persist(gavin);
+
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add(enrolment);
+		s.persist(enrolment);
+
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		DetachedCriteria dc = DetachedCriteria.forClass(Student.class)
+			.add( Property.forName("studentNumber").eq( new Long(232) ) )
+			.setProjection( Property.forName("name") );
+		gavin = ( Student ) s.createCriteria(Student.class)
+			.add( Subqueries.exists(dc) )
+			.setReadOnly( true )
+			.uniqueResult();
+		assertFalse( s.isDefaultReadOnly() );
+		assertTrue( s.isReadOnly( gavin ) );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		Hibernate.initialize( gavin.getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( gavin.getPreferredCourse() ) );
+		checkProxyReadOnly( s, gavin.getPreferredCourse(), true );
+		assertFalse( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		Hibernate.initialize( gavin.getEnrolments() );
+		assertTrue( Hibernate.isInitialized( gavin.getEnrolments() ) );
+		assertEquals( 1, gavin.getEnrolments().size() );
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		assertFalse( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		Hibernate.initialize( enrolment.getCourse() );
+		checkProxyReadOnly( s, enrolment.getCourse(), false );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		DetachedCriteria dc2 = DetachedCriteria.forClass(Student.class, "st")
+			.add( Property.forName("st.studentNumber").eqProperty("e.studentNumber") )
+			.setProjection( Property.forName("name") );
+		enrolment = ( Enrolment ) s.createCriteria(Enrolment.class, "e")
+			.add( Subqueries.eq("Gavin King", dc2) )
+			.setReadOnly( true )
+			.uniqueResult();
+		assertTrue( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		Hibernate.initialize( enrolment.getCourse() );
+		assertTrue( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		assertFalse( Hibernate.isInitialized( enrolment.getStudent() ) );
+		checkProxyReadOnly( s, enrolment.getStudent(), true );
+		Hibernate.initialize( enrolment.getStudent() );
+		assertTrue( Hibernate.isInitialized( enrolment.getStudent() ) );
+		checkProxyReadOnly( s, enrolment.getStudent(), true );
+		assertFalse( Hibernate.isInitialized( enrolment.getStudent().getPreferredCourse() ) );
+		checkProxyReadOnly( s, enrolment.getStudent().getPreferredCourse(), false );
+		Hibernate.initialize( enrolment.getStudent().getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( enrolment.getStudent().getPreferredCourse() ) );
+		checkProxyReadOnly( s, enrolment.getStudent().getPreferredCourse(), false );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		DetachedCriteria dc3 = DetachedCriteria.forClass(Student.class, "st")
+			.createCriteria("enrolments")
+				.createCriteria("course")
+					.add( Property.forName("description").eq("Hibernate Training") )
+					.setProjection( Property.forName("st.name") );
+		enrolment = ( Enrolment ) s.createCriteria(Enrolment.class, "e")
+			.add( Subqueries.eq("Gavin King", dc3) )
+			.setReadOnly( true )
+			.uniqueResult();
+		assertTrue( s.isReadOnly( enrolment ) );
+		assertFalse( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		Hibernate.initialize( enrolment.getCourse() );
+		assertTrue( Hibernate.isInitialized( enrolment.getCourse() ) );
+		checkProxyReadOnly( s, enrolment.getCourse(), true );
+		assertFalse( Hibernate.isInitialized( enrolment.getStudent() ) );
+		checkProxyReadOnly( s, enrolment.getStudent(), true );
+		Hibernate.initialize( enrolment.getStudent() );
+		assertTrue( Hibernate.isInitialized( enrolment.getStudent() ) );
+		checkProxyReadOnly( s, enrolment.getStudent(), true );
+		assertFalse( Hibernate.isInitialized( enrolment.getStudent().getPreferredCourse() ) );
+		checkProxyReadOnly( s, enrolment.getStudent().getPreferredCourse(), false );
+		Hibernate.initialize( enrolment.getStudent().getPreferredCourse() );
+		assertTrue( Hibernate.isInitialized( enrolment.getStudent().getPreferredCourse() ) );
+		checkProxyReadOnly( s, enrolment.getStudent().getPreferredCourse(), false );
+		t.commit();
+		s.close();
+
+		s = openSession();
+		t = s.beginTransaction();
+		s.delete(gavin.getPreferredCourse());
+		s.delete(gavin);
+		enrolment = ( Enrolment ) gavin.getEnrolments().iterator().next();
+		s.delete( enrolment.getCourse() );
+		s.delete(enrolment);
+		t.commit();
+		s.close();		
+	}
+	
+	public void testDetachedCriteria() {
+		
+		DetachedCriteria dc = DetachedCriteria.forClass(Student.class)
+			.add( Property.forName("name").eq("Gavin King") )
+			.addOrder( Order.asc("studentNumber") );
+		
+		byte[] bytes = SerializationHelper.serialize(dc);
+		
+		dc = (DetachedCriteria) SerializationHelper.deserialize(bytes);
+		
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		Student bizarroGavin = new Student();
+		bizarroGavin.setName("Gavin King");
+		bizarroGavin.setStudentNumber(666);
+		session.persist(bizarroGavin);
+		session.persist(gavin);
+
+		t.commit();
+		session.close();
+
+		session = openSession();
+		t = session.beginTransaction();
+
+		List result = dc.getExecutableCriteria(session)
+			.setMaxResults(3)
+			.setReadOnly( true )
+			.list();
+
+		assertEquals( result.size(), 2 );
+		gavin = ( Student ) result.get( 0 );
+		bizarroGavin = ( Student ) result.get( 1 );
+		assertEquals( 232, gavin.getStudentNumber() );
+		assertEquals( 666, bizarroGavin.getStudentNumber() );
+		assertTrue( session.isReadOnly( gavin ) );
+		assertTrue( session.isReadOnly( bizarroGavin ) );
+
+		session.delete(gavin);
+		session.delete(bizarroGavin);
+		t.commit();
+		session.close();
+	}
+	
+		public void testTwoAliasesCache() {
+			Session s = openSession();
+			Transaction t = s.beginTransaction();
+			
+			Course course = new Course();
+			course.setCourseCode("HIB");
+			course.setDescription("Hibernate Training");
+			s.save(course);
+			
+			Student gavin = new Student();
+			gavin.setName("Gavin King");
+			gavin.setStudentNumber(666);
+			s.save(gavin);
+			
+			Student xam = new Student();
+			xam.setName("Max Rydahl Andersen");
+			xam.setStudentNumber(101);
+			s.save(xam);
+			
+			Enrolment enrolment1 = new Enrolment();
+			enrolment1.setCourse(course);
+			enrolment1.setCourseCode(course.getCourseCode());
+			enrolment1.setSemester((short) 1);
+			enrolment1.setYear((short) 1999);
+			enrolment1.setStudent(xam);
+			enrolment1.setStudentNumber(xam.getStudentNumber());
+			xam.getEnrolments().add(enrolment1);
+			s.save(enrolment1);
+			
+			Enrolment enrolment2 = new Enrolment();
+			enrolment2.setCourse(course);
+			enrolment2.setCourseCode(course.getCourseCode());
+			enrolment2.setSemester((short) 3);
+			enrolment2.setYear((short) 1998);
+			enrolment2.setStudent(gavin);
+			enrolment2.setStudentNumber(gavin.getStudentNumber());
+			gavin.getEnrolments().add(enrolment2);
+			s.save(enrolment2);
+			t.commit();
+			s.close();
+
+			s = openSession();
+			t = s.beginTransaction();
+			
+			List list = s.createCriteria(Enrolment.class)
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setCacheable(true)
+				.setReadOnly( true )
+				.list();
+			
+			assertEquals( list.size(), 2 );
+
+			Enrolment e = ( Enrolment ) list.get( 0 );
+			if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment1 = e;
+				enrolment2 = ( Enrolment ) list.get( 1 );
+			}
+			else if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment2 = e;
+				enrolment1 = ( Enrolment ) list.get( 1 );
+			}
+			else {
+				fail( "Enrolment has unknown student number: " + e.getStudent().getStudentNumber() );
+			}
+
+			assertTrue( s.isReadOnly( enrolment1 ) );
+			assertTrue( s.isReadOnly( enrolment2 ) );
+			assertTrue( s.isReadOnly( enrolment1.getCourse() ) );
+			assertTrue( s.isReadOnly( enrolment2.getCourse() ) );
+			assertSame( enrolment1.getCourse(), enrolment2.getCourse() );
+			assertTrue( s.isReadOnly( enrolment1.getStudent() ) );
+			assertTrue( s.isReadOnly( enrolment2.getStudent() ) );
+
+			t.commit();
+			s.close();
+	
+			s = openSession();
+			t = s.beginTransaction();
+			
+			list = s.createCriteria(Enrolment.class)
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.setReadOnly( true )
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setCacheable(true)
+				.setReadOnly( true )
+				.list();
+		
+			assertEquals( list.size(), 2 );
+
+			e = ( Enrolment ) list.get( 0 );
+			if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment1 = e;
+				enrolment2 = ( Enrolment ) list.get( 1 );
+			}
+			else if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment2 = e;
+				enrolment1 = ( Enrolment ) list.get( 1 );
+			}
+			else {
+				fail( "Enrolment has unknown student number: " + e.getStudent().getStudentNumber() );
+			}
+
+			assertTrue( s.isReadOnly( enrolment1 ) );
+			assertTrue( s.isReadOnly( enrolment2 ) );
+			assertTrue( s.isReadOnly( enrolment1.getCourse() ) );
+			assertTrue( s.isReadOnly( enrolment2.getCourse() ) );
+			assertSame( enrolment1.getCourse(), enrolment2.getCourse() );
+			assertTrue( s.isReadOnly( enrolment1.getStudent() ) );
+			assertTrue( s.isReadOnly( enrolment2.getStudent() ) );
+
+			t.commit();
+			s.close();
+	
+			s = openSession();
+			t = s.beginTransaction();
+			
+			list = s.createCriteria(Enrolment.class)
+				.setReadOnly( true )
+				.createAlias("student", "s")
+				.createAlias("course", "c")
+				.add( Restrictions.isNotEmpty("s.enrolments") )
+				.setCacheable(true)
+				.list();
+			
+			assertEquals( list.size(), 2 );
+
+			e = ( Enrolment ) list.get( 0 );
+			if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment1 = e;
+				enrolment2 = ( Enrolment ) list.get( 1 );
+			}
+			else if ( e.getStudent().getStudentNumber() == xam.getStudentNumber() ) {
+				enrolment2 = e;
+				enrolment1 = ( Enrolment ) list.get( 1 );
+			}
+			else {
+				fail( "Enrolment has unknown student number: " + e.getStudent().getStudentNumber() );
+			}
+
+			assertTrue( s.isReadOnly( enrolment1 ) );
+			assertTrue( s.isReadOnly( enrolment2 ) );
+			assertTrue( s.isReadOnly( enrolment1.getCourse() ) );
+			assertTrue( s.isReadOnly( enrolment2.getCourse() ) );
+			assertSame( enrolment1.getCourse(), enrolment2.getCourse() );
+			assertTrue( s.isReadOnly( enrolment1.getStudent() ) );
+			assertTrue( s.isReadOnly( enrolment2.getStudent() ) );
+
+			s.delete( enrolment1 );
+			s.delete( enrolment2 );
+			s.delete( enrolment1.getCourse() );
+			s.delete( enrolment1.getStudent() );
+			s.delete( enrolment2.getStudent() );
+		
+			t.commit();
+			s.close();
+	}
+
+	/*
+	public void testProjectionsUsingProperty() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		
+		Course course = new Course();
+		course.setCourseCode("HIB");
+		course.setDescription("Hibernate Training");
+		s.save(course);
+		
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(667);
+		s.save(gavin);
+		
+		Student xam = new Student();
+		xam.setName("Max Rydahl Andersen");
+		xam.setStudentNumber(101);
+		s.save(xam);
+		
+		Enrolment enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 1);
+		enrolment.setYear((short) 1999);
+		enrolment.setStudent(xam);
+		enrolment.setStudentNumber(xam.getStudentNumber());
+		xam.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		enrolment = new Enrolment();
+		enrolment.setCourse(course);
+		enrolment.setCourseCode(course.getCourseCode());
+		enrolment.setSemester((short) 3);
+		enrolment.setYear((short) 1998);
+		enrolment.setStudent(gavin);
+		enrolment.setStudentNumber(gavin.getStudentNumber());
+		gavin.getEnrolments().add(enrolment);
+		s.save(enrolment);
+		
+		s.flush();
+		
+		Long count = (Long) s.createCriteria(Enrolment.class)
+			.setProjection( Property.forName("studentNumber").count().setDistinct() )
+			.uniqueResult();
+		assertEquals(count, new Long(2));
+		
+		Object object = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("studentNumber").count() )
+					.add( Property.forName("studentNumber").max() )
+					.add( Property.forName("studentNumber").min() )
+					.add( Property.forName("studentNumber").avg() )
+			)
+			.uniqueResult();
+		Object[] result = (Object[])object; 
+		
+		assertEquals(new Long(2),result[0]);
+		assertEquals(new Long(667),result[1]);
+		assertEquals(new Long(101),result[2]);
+		assertEquals(384.0, ( (Double) result[3] ).doubleValue(), 0.01);
+		
+		
+		s.createCriteria(Enrolment.class)
+		    .add( Property.forName("studentNumber").gt( new Long(665) ) )
+		    .add( Property.forName("studentNumber").lt( new Long(668) ) )
+		    .add( Property.forName("courseCode").like("HIB", MatchMode.START) )
+		    .add( Property.forName("year").eq( new Short( (short) 1999 ) ) )
+		    .addOrder( Property.forName("studentNumber").asc() )
+			.uniqueResult();
+	
+		List resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("studentNumber").as("stNumber") )
+					.add( Property.forName("courseCode").as("cCode") )
+			)
+		    .add( Property.forName("studentNumber").gt( new Long(665) ) )
+		    .add( Property.forName("studentNumber").lt( new Long(668) ) )
+		    .addOrder( Property.forName("studentNumber").asc() )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(1, resultWithMaps.size());
+		Map m1 = (Map) resultWithMaps.get(0);
+		
+		assertEquals(new Long(667), m1.get("stNumber"));
+		assertEquals(course.getCourseCode(), m1.get("cCode"));		
+
+		resultWithMaps = s.createCriteria(Enrolment.class)
+			.setProjection( Property.forName("studentNumber").as("stNumber") )
+		    .addOrder( Order.desc("stNumber") )
+			.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+			.list();
+		
+		assertEquals(2, resultWithMaps.size());
+		Map m0 = (Map) resultWithMaps.get(0);
+		m1 = (Map) resultWithMaps.get(1);
+		
+		assertEquals(new Long(101), m1.get("stNumber"));
+		assertEquals(new Long(667), m0.get("stNumber"));
+
+	
+		List resultWithAliasedBean = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("st.name").as("studentName") )
+					.add( Property.forName("co.description").as("courseDescription") )
+			)
+			.addOrder( Order.desc("studentName") )
+			.setResultTransformer( Transformers.aliasToBean(StudentDTO.class) )
+			.list();
+		
+		assertEquals(2, resultWithAliasedBean.size());
+		
+		StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);
+		assertNotNull(dto.getDescription());
+		assertNotNull(dto.getName());
+	
+		s.createCriteria(Student.class)
+			.add( Restrictions.like("name", "Gavin", MatchMode.START) )
+			.addOrder( Order.asc("name") )
+			.createCriteria("enrolments", "e")
+				.addOrder( Order.desc("year") )
+				.addOrder( Order.desc("semester") )
+			.createCriteria("course","c")
+				.addOrder( Order.asc("description") )
+				.setProjection( Projections.projectionList()
+					.add( Property.forName("this.name") )
+					.add( Property.forName("e.year") )
+					.add( Property.forName("e.semester") )
+					.add( Property.forName("c.courseCode") )
+					.add( Property.forName("c.description") )
+				)
+			.uniqueResult();
+			
+		Projection p1 = Projections.projectionList()
+			.add( Property.forName("studentNumber").count() )
+			.add( Property.forName("studentNumber").max() )
+			.add( Projections.rowCount() );
+		
+		Projection p2 = Projections.projectionList()
+			.add( Property.forName("studentNumber").min() )
+			.add( Property.forName("studentNumber").avg() )
+			.add( Projections.sqlProjection(
+					"1 as constOne, count(*) as countStar", 
+					new String[] { "constOne", "countStar" }, 
+					new Type[] { Hibernate.INTEGER, Hibernate.INTEGER }
+			) );
+	
+		Object[] array = (Object[]) s.createCriteria(Enrolment.class)
+			.setProjection( Projections.projectionList().add(p1).add(p2) )
+			.uniqueResult();
+		
+		assertEquals( array.length, 7 );
+		
+		List list = s.createCriteria(Enrolment.class)
+			.createAlias("student", "st")
+			.createAlias("course", "co")
+			.setProjection( Projections.projectionList()
+					.add( Property.forName("co.courseCode").group() )
+					.add( Property.forName("st.studentNumber").count().setDistinct() )
+					.add( Property.forName("year").group() )
+			)
+			.list();
+		
+		assertEquals( list.size(), 2 );
+		
+		s.delete(gavin);
+		s.delete(xam);
+		s.delete(course);
+		
+		t.commit();
+		s.close();
+	}
+
+	public void testRestrictionOnSubclassCollection() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		s.createCriteria( Reptile.class )
+				.add( Restrictions.isEmpty( "offspring" ) )
+				.list();
+
+		s.createCriteria( Reptile.class )
+				.add( Restrictions.isNotEmpty( "offspring" ) )
+				.list();
+
+		t.rollback();
+		s.close();
+	}
+
+	public void testClassProperty() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+
+		// HQL: from Animal a where a.mother.class = Reptile
+		Criteria c = s.createCriteria(Animal.class,"a")
+			.createAlias("mother","m")
+			.add( Property.forName("m.class").eq(Reptile.class) );
+		c.list();
+		t.rollback();
+		s.close();
+	}
+
+	public void testProjectedId() {
+		Session s = openSession();
+		Transaction t = s.beginTransaction();
+		s.createCriteria(Course.class).setProjection( Projections.property("courseCode") ).list();
+		s.createCriteria(Course.class).setProjection( Projections.id() ).list();
+		t.rollback();
+		s.close();
+	}
+
+	public void testSubcriteriaJoinTypes() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course courseA = new Course();
+		courseA.setCourseCode("HIB-A");
+		courseA.setDescription("Hibernate Training A");
+		session.persist(courseA);
+
+		Course courseB = new Course();
+		courseB.setCourseCode("HIB-B");
+		courseB.setDescription("Hibernate Training B");
+		session.persist(courseB);
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse(courseA);
+		session.persist(gavin);
+
+		Student leonardo = new Student();
+		leonardo.setName("Leonardo Quijano");
+		leonardo.setStudentNumber(233);
+		leonardo.setPreferredCourse(courseB);
+		session.persist(leonardo);
+
+		Student johnDoe = new Student();
+		johnDoe.setName("John Doe");
+		johnDoe.setStudentNumber(235);
+		johnDoe.setPreferredCourse(null);
+		session.persist(johnDoe);
+
+		List result = session.createCriteria( Student.class )
+				.setProjection( Property.forName("preferredCourse.courseCode") )
+				.createCriteria( "preferredCourse", Criteria.LEFT_JOIN )
+						.addOrder( Order.asc( "courseCode" ) )
+						.list();
+		assertEquals( 3, result.size() );
+		// can't be sure of NULL comparison ordering aside from they should
+		// either come first or last
+		if ( result.get( 0 ) == null ) {
+			assertEquals( "HIB-A", result.get(1) );
+			assertEquals( "HIB-B", result.get(2) );
+		}
+		else {
+			assertNull( result.get(2) );
+			assertEquals( "HIB-A", result.get(0) );
+			assertEquals( "HIB-B", result.get(1) );
+		}
+
+		result = session.createCriteria( Student.class )
+				.setFetchMode( "preferredCourse", FetchMode.JOIN )
+				.createCriteria( "preferredCourse", Criteria.LEFT_JOIN )
+						.addOrder( Order.asc( "courseCode" ) )
+						.list();
+		assertEquals( 3, result.size() );
+		assertNotNull( result.get(0) );
+		assertNotNull( result.get(1) );
+		assertNotNull( result.get(2) );
+
+		result = session.createCriteria( Student.class )
+				.setFetchMode( "preferredCourse", FetchMode.JOIN )
+				.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN )
+				.addOrder( Order.asc( "pc.courseCode" ) )
+				.list();
+		assertEquals( 3, result.size() );
+		assertNotNull( result.get(0) );
+		assertNotNull( result.get(1) );
+		assertNotNull( result.get(2) );
+
+		session.delete(gavin);
+		session.delete(leonardo);
+		session.delete(johnDoe);
+		session.delete(courseA);
+		session.delete(courseB);
+		t.commit();
+		session.close();
+	}
+	
+	public void testAliasJoinCriterion() {
+		Session session = openSession();
+		Transaction t = session.beginTransaction();
+
+		Course courseA = new Course();
+		courseA.setCourseCode("HIB-A");
+		courseA.setDescription("Hibernate Training A");
+		session.persist(courseA);
+
+		Course courseB = new Course();
+		courseB.setCourseCode("HIB-B");
+		courseB.setDescription("Hibernate Training B");
+		session.persist(courseB);
+
+		Student gavin = new Student();
+		gavin.setName("Gavin King");
+		gavin.setStudentNumber(232);
+		gavin.setPreferredCourse(courseA);
+		session.persist(gavin);
+
+		Student leonardo = new Student();
+		leonardo.setName("Leonardo Quijano");
+		leonardo.setStudentNumber(233);
+		leonardo.setPreferredCourse(courseB);
+		session.persist(leonardo);
+
+		Student johnDoe = new Student();
+		johnDoe.setName("John Doe");
+		johnDoe.setStudentNumber(235);
+		johnDoe.setPreferredCourse(null);
+		session.persist(johnDoe);
+
+		// test == on one value exists
+		List result = session.createCriteria( Student.class )
+			.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.eq("pc.courseCode", "HIB-A") )
+			.setProjection( Property.forName("pc.courseCode") )
+			.addOrder(Order.asc("pc.courseCode"))
+			.list();
+		
+		assertEquals( 3, result.size() );
+		
+		// can't be sure of NULL comparison ordering aside from they should
+		// either come first or last
+		if ( result.get( 0 ) == null ) {
+			assertNull(result.get(1));
+			assertEquals( "HIB-A", result.get(2) );
+		}
+		else {
+			assertNull( result.get(2) );
+			assertNull( result.get(1) );
+			assertEquals( "HIB-A", result.get(0) );
+		}
+		
+		// test == on non existent value
+		result = session.createCriteria( Student.class )
+		.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.eq("pc.courseCode", "HIB-R") )
+		.setProjection( Property.forName("pc.courseCode") )
+		.addOrder(Order.asc("pc.courseCode"))
+		.list();
+	
+		assertEquals( 3, result.size() );
+		assertNull( result.get(2) );
+		assertNull( result.get(1) );
+		assertNull(result.get(0) );
+		
+		// test != on one existing value
+		result = session.createCriteria( Student.class )
+		.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.ne("pc.courseCode", "HIB-A") )
+		.setProjection( Property.forName("pc.courseCode") )
+		.addOrder(Order.asc("pc.courseCode"))
+		.list();
+	
+		assertEquals( 3, result.size() );
+		// can't be sure of NULL comparison ordering aside from they should
+		// either come first or last
+		if ( result.get( 0 ) == null ) {
+			assertNull( result.get(1) );
+			assertEquals( "HIB-B", result.get(2) );
+		}
+		else {
+			assertEquals( "HIB-B", result.get(0) );
+			assertNull( result.get(1) );
+			assertNull( result.get(2) );
+		}
+
+		session.delete(gavin);
+		session.delete(leonardo);
+		session.delete(johnDoe);
+		session.delete(courseA);
+		session.delete(courseB);
+		t.commit();
+		session.close();
+	}
+	*/
+	
+	private void checkProxyReadOnly(Session s, Object proxy, boolean expectedReadOnly) {
+		assertTrue( proxy instanceof HibernateProxy );
+		LazyInitializer li = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer();
+		assertSame( s, li.getSession() );
+		assertEquals( expectedReadOnly, s.isReadOnly( proxy ) );
+		assertEquals( expectedReadOnly, li.isReadOnly() );
+		assertEquals( Hibernate.isInitialized( proxy ), ! li.isUninitialized() );
+		if ( Hibernate.isInitialized( proxy ) ) {
+			assertEquals( expectedReadOnly, s.isReadOnly( li.getImplementation() ) );
+		}
+	}
+
+}
+


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/ReadOnlyCriteriaQueryTest.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Student.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Student.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Student.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,47 @@
+//$Id: Student.java 9116 2006-01-23 21:21:01Z steveebersole $
+package org.hibernate.test.readonly.criteria;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gavin King
+ */
+public class Student {
+	private long studentNumber;
+	private String name;
+	private Course preferredCourse;
+	private Set enrolments = new HashSet();
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public long getStudentNumber() {
+		return studentNumber;
+	}
+
+	public void setStudentNumber(long studentNumber) {
+		this.studentNumber = studentNumber;
+	}
+
+	public Course getPreferredCourse() {
+		return preferredCourse;
+	}
+
+	public void setPreferredCourse(Course preferredCourse) {
+		this.preferredCourse = preferredCourse;
+	}
+
+	public Set getEnrolments() {
+		return enrolments;
+	}
+
+	public void setEnrolments(Set employments) {
+		this.enrolments = employments;
+	}
+}


Property changes on: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/Student.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/StudentDTO.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/StudentDTO.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/readonly/criteria/StudentDTO.java	2010-02-10 07:00:59 UTC (rev 18758)
@@ -0,0 +1,26 @@
+/*
+ * Created on 28-Jan-2005
+ *
+ */
+package org.hibernate.test.readonly.criteria;
+
+/**
+ * @author max
+ *
+ */
+public class StudentDTO {
+
+	private String studentName;
+	private String courseDescription;
+
+	public StudentDTO() { }
+	
+	public String getName() {
+		return studentName;
+	}
+	
+	public String getDescription() {
+		return courseDescription;
+	}
+	
+}



More information about the hibernate-commits mailing list