Session.setReadOnly(Object, boolean) fails for proxies
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18525 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
8bed8a1c22
commit
cc382233c5
|
@ -839,15 +839,29 @@ public interface Session extends Serializable {
|
||||||
* Get the statistics for this session.
|
* Get the statistics for this session.
|
||||||
*/
|
*/
|
||||||
public SessionStatistics getStatistics();
|
public SessionStatistics getStatistics();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an unmodified persistent object to read only mode, or a read only
|
* Is the specified entity or proxy read-only?
|
||||||
* object to modifiable mode. In read only mode, no snapshot is maintained
|
* @param entityOrProxy, an entity or HibernateProxy
|
||||||
|
* @return true, the entity or proxy is read-only;
|
||||||
|
* false, the entity or proxy is modifiable.
|
||||||
|
*/
|
||||||
|
public boolean isReadOnly(Object entityOrProxy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an unmodified persistent object to read-only mode, or a read-only
|
||||||
|
* object to modifiable mode. In read-only mode, no snapshot is maintained
|
||||||
* and the instance is never dirty checked.
|
* and the instance is never dirty checked.
|
||||||
|
*
|
||||||
|
* If the entity or proxy already has the specified read-only/modifiable
|
||||||
|
* setting, then this method does nothing.
|
||||||
*
|
*
|
||||||
|
* @param entityOrProxy, an entity or HibernateProxy
|
||||||
|
* @param readOnly, if true, the entity or proxy is made read-only;
|
||||||
|
* if false, the entity or proxy is made modifiable.
|
||||||
* @see Query#setReadOnly(boolean)
|
* @see Query#setReadOnly(boolean)
|
||||||
*/
|
*/
|
||||||
public void setReadOnly(Object entity, boolean readOnly);
|
public void setReadOnly(Object entityOrProxy, boolean readOnly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for allowing users to perform JDBC related work using the Connection
|
* Controller for allowing users to perform JDBC related work using the Connection
|
||||||
|
|
|
@ -261,22 +261,25 @@ public final class EntityEntry implements Serializable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
if (status != Status.MANAGED && status != Status.READ_ONLY) {
|
||||||
|
throw new HibernateException("instance was not in a valid state");
|
||||||
|
}
|
||||||
|
return status == Status.READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
public void setReadOnly(boolean readOnly, Object entity) {
|
public void setReadOnly(boolean readOnly, Object entity) {
|
||||||
if ( ( readOnly && status == Status.READ_ONLY ) ||
|
if ( readOnly == isReadOnly() ) {
|
||||||
( ( ! readOnly ) && status == Status.MANAGED ) ) {
|
|
||||||
// simply return since the status is not being changed
|
// simply return since the status is not being changed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (status!=Status.MANAGED && status!=Status.READ_ONLY) {
|
if ( readOnly ) {
|
||||||
throw new HibernateException("instance was not in a valid state");
|
setStatus( Status.READ_ONLY );
|
||||||
}
|
|
||||||
if (readOnly) {
|
|
||||||
setStatus(Status.READ_ONLY);
|
|
||||||
loadedState = null;
|
loadedState = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setStatus(Status.MANAGED);
|
setStatus( Status.MANAGED );
|
||||||
loadedState = getPersister().getPropertyValues(entity, entityMode);
|
loadedState = getPersister().getPropertyValues( entity, entityMode );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -475,11 +475,26 @@ public interface PersistenceContext {
|
||||||
* Is the association property belonging to the keyed entity null?
|
* Is the association property belonging to the keyed entity null?
|
||||||
*/
|
*/
|
||||||
public boolean isPropertyNull(EntityKey ownerKey, String propertyName);
|
public boolean isPropertyNull(EntityKey ownerKey, String propertyName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the object to read only and discard it's snapshot
|
* Is the entity or proxy read-only?
|
||||||
|
*
|
||||||
|
* @param entityOrProxy
|
||||||
|
* @return true, the object is read-only; false, the object is modifiable.
|
||||||
*/
|
*/
|
||||||
public void setReadOnly(Object entity, boolean readOnly);
|
public boolean isReadOnly(Object entityOrProxy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the entity or proxy to read only and discard it's snapshot.
|
||||||
|
*
|
||||||
|
* If the entity or proxy already has the specified read-only/modifiable
|
||||||
|
* setting, then this method does nothing.
|
||||||
|
*
|
||||||
|
* @param entityOrProxy, an entity or HibernateProxy
|
||||||
|
* @param readOnly, if true, the entity or proxy is made read-only;
|
||||||
|
* if false, the entity or proxy is made modifiable.
|
||||||
|
*/
|
||||||
|
public void setReadOnly(Object entityOrProxy, boolean readOnly);
|
||||||
|
|
||||||
void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId);
|
void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId);
|
||||||
|
|
||||||
|
|
|
@ -1302,13 +1302,67 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
||||||
nullAssociations.clear();
|
nullAssociations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReadOnly(Object entity, boolean readOnly) {
|
public boolean isReadOnly(Object entityOrProxy) {
|
||||||
EntityEntry entry = getEntry(entity);
|
if ( entityOrProxy == null ) {
|
||||||
if (entry==null) {
|
throw new AssertionFailure( "object must be non-null." );
|
||||||
throw new TransientObjectException("Instance was not associated with the session");
|
|
||||||
}
|
}
|
||||||
entry.setReadOnly(readOnly, entity);
|
boolean isReadOnly;
|
||||||
hasNonReadOnlyEntities = hasNonReadOnlyEntities || !readOnly;
|
if ( entityOrProxy instanceof HibernateProxy ) {
|
||||||
|
isReadOnly = ( ( HibernateProxy ) entityOrProxy ).getHibernateLazyInitializer().isReadOnly();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EntityEntry ee = getEntry( entityOrProxy );
|
||||||
|
if ( ee == null ) {
|
||||||
|
throw new TransientObjectException("Instance was not associated with this persistence context" );
|
||||||
|
}
|
||||||
|
isReadOnly = ee.isReadOnly();
|
||||||
|
}
|
||||||
|
return isReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadOnly(Object object, boolean readOnly) {
|
||||||
|
if ( object == null ) {
|
||||||
|
throw new AssertionFailure( "object must be non-null." );
|
||||||
|
}
|
||||||
|
if ( isReadOnly( object ) == readOnly ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( object instanceof HibernateProxy ) {
|
||||||
|
HibernateProxy proxy = ( HibernateProxy ) object;
|
||||||
|
setProxyReadOnly( proxy, readOnly );
|
||||||
|
if ( Hibernate.isInitialized( proxy ) ) {
|
||||||
|
setEntityReadOnly(
|
||||||
|
proxy.getHibernateLazyInitializer().getImplementation(),
|
||||||
|
readOnly
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setEntityReadOnly( object, readOnly );
|
||||||
|
// PersistenceContext.proxyFor( entity ) returns entity if there is no proxy for that entity
|
||||||
|
// so need to check the return value to be sure it is really a proxy
|
||||||
|
Object maybeProxy = getSession().getPersistenceContext().proxyFor( object );
|
||||||
|
if ( maybeProxy instanceof HibernateProxy ) {
|
||||||
|
setProxyReadOnly( ( HibernateProxy ) maybeProxy, readOnly );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setProxyReadOnly(HibernateProxy proxy, boolean readOnly) {
|
||||||
|
if ( proxy.getHibernateLazyInitializer().getSession() != getSession() ) {
|
||||||
|
throw new AssertionFailure(
|
||||||
|
"Attempt to set a proxy to read-only that is associated with a different session" );
|
||||||
|
}
|
||||||
|
proxy.getHibernateLazyInitializer().setReadOnly( readOnly );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setEntityReadOnly(Object entity, boolean readOnly) {
|
||||||
|
EntityEntry entry = getEntry(entity);
|
||||||
|
if (entry == null) {
|
||||||
|
throw new TransientObjectException("Instance was not associated with this persistence context" );
|
||||||
|
}
|
||||||
|
entry.setReadOnly(readOnly, entity );
|
||||||
|
hasNonReadOnlyEntities = hasNonReadOnlyEntities || ! readOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
|
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.cache.CacheKey;
|
import org.hibernate.cache.CacheKey;
|
||||||
import org.hibernate.cache.entry.CacheEntry;
|
import org.hibernate.cache.entry.CacheEntry;
|
||||||
import org.hibernate.event.PostLoadEvent;
|
import org.hibernate.event.PostLoadEvent;
|
||||||
|
@ -188,8 +189,18 @@ public final class TwoPhaseLoad {
|
||||||
factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
|
factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( readOnly || !persister.isMutable() ) {
|
boolean isReallyReadOnly = readOnly || !persister.isMutable();
|
||||||
|
Object proxy = persistenceContext.getProxy(
|
||||||
|
new EntityKey(entityEntry.getId(), entityEntry.getPersister(), session.getEntityMode()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if ( proxy != null ) {
|
||||||
|
// there is already a proxy for this impl
|
||||||
|
// only set the status to read-only if the proxy is read-only
|
||||||
|
isReallyReadOnly = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().isReadOnly();
|
||||||
|
}
|
||||||
|
if ( isReallyReadOnly ) {
|
||||||
//no need to take a snapshot - this is a
|
//no need to take a snapshot - this is a
|
||||||
//performance optimization, but not really
|
//performance optimization, but not really
|
||||||
//important, except for entities with huge
|
//important, except for entities with huge
|
||||||
|
|
|
@ -1956,6 +1956,12 @@ public final class SessionImpl extends AbstractSessionImpl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isReadOnly(Object entityOrProxy) {
|
||||||
|
errorIfClosed();
|
||||||
|
checkTransactionSynchStatus();
|
||||||
|
return persistenceContext.isReadOnly( entityOrProxy );
|
||||||
|
}
|
||||||
|
|
||||||
public void setReadOnly(Object entity, boolean readOnly) {
|
public void setReadOnly(Object entity, boolean readOnly) {
|
||||||
errorIfClosed();
|
errorIfClosed();
|
||||||
checkTransactionSynchStatus();
|
checkTransactionSynchStatus();
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LazyInitializationException;
|
import org.hibernate.LazyInitializationException;
|
||||||
|
import org.hibernate.TransientObjectException;
|
||||||
|
import org.hibernate.SessionException;
|
||||||
import org.hibernate.engine.EntityKey;
|
import org.hibernate.engine.EntityKey;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
|
||||||
|
@ -43,8 +45,8 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
private Serializable id;
|
private Serializable id;
|
||||||
private Object target;
|
private Object target;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
|
private boolean readOnly;
|
||||||
private boolean unwrap;
|
private boolean unwrap;
|
||||||
|
|
||||||
private transient SessionImplementor session;
|
private transient SessionImplementor session;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +65,15 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
|
protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.session = session;
|
// initialize other fields depending on session state
|
||||||
|
if ( session == null ) {
|
||||||
|
// would be better to call unsetSession(), but it is not final...
|
||||||
|
session = null;
|
||||||
|
readOnly = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setSession( session );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,7 +118,9 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
if ( s != session ) {
|
if ( s != session ) {
|
||||||
// check for s == null first, since it is least expensive
|
// check for s == null first, since it is least expensive
|
||||||
if ( s == null ){
|
if ( s == null ){
|
||||||
unsetSession();
|
// would be better to call unsetSession(), but it is not final...
|
||||||
|
session = null;
|
||||||
|
readOnly = false;
|
||||||
}
|
}
|
||||||
else if ( isConnectedToSession() ) {
|
else if ( isConnectedToSession() ) {
|
||||||
//TODO: perhaps this should be some other RuntimeException...
|
//TODO: perhaps this should be some other RuntimeException...
|
||||||
|
@ -116,6 +128,8 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
session = s;
|
session = s;
|
||||||
|
// NOTE: the proxy may not be connected to the session yet, so set readOnly directly
|
||||||
|
readOnly = ! session.getFactory().getEntityPersister( entityName ).isMutable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +146,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
*/
|
*/
|
||||||
public void unsetSession() {
|
public void unsetSession() {
|
||||||
session = null;
|
session = null;
|
||||||
|
readOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,6 +235,48 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
errorIfReadOnlySettingNotAvailable();
|
||||||
|
if ( !isConnectedToSession() ) {
|
||||||
|
throw new TransientObjectException(
|
||||||
|
"The read-only/modifiable setting is only accessible when the proxy is associated with a session." );
|
||||||
|
}
|
||||||
|
return readOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public void setReadOnly(boolean readOnly) {
|
||||||
|
errorIfReadOnlySettingNotAvailable();
|
||||||
|
// only update if readOnly is different from current setting
|
||||||
|
if ( this.readOnly != readOnly ) {
|
||||||
|
Object proxy = getProxyOrNull();
|
||||||
|
if ( proxy == null ) {
|
||||||
|
throw new TransientObjectException(
|
||||||
|
"Cannot set the read-only/modifiable mode unless the proxy is associated with a session." );
|
||||||
|
}
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
if ( initialized ) {
|
||||||
|
session.getPersistenceContext().setReadOnly( target, readOnly );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void errorIfReadOnlySettingNotAvailable() {
|
||||||
|
if ( session == null ) {
|
||||||
|
throw new TransientObjectException(
|
||||||
|
"Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session." );
|
||||||
|
}
|
||||||
|
if ( session.isClosed() ) {
|
||||||
|
throw new SessionException(
|
||||||
|
"Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -104,6 +104,37 @@ public interface LazyInitializer {
|
||||||
*/
|
*/
|
||||||
public void setImplementation(Object target);
|
public void setImplementation(Object target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the proxy read-only?.
|
||||||
|
*
|
||||||
|
* @return true, if this proxy is read-only; false, otherwise
|
||||||
|
* @throws org.hibernate.TransientObjectException if the proxy is not association with a session
|
||||||
|
* @throws org.hibernate.SessionException if the proxy is associated with a sesssion that is closed
|
||||||
|
*
|
||||||
|
* @see org.hibernate.Session#isReadOnly(Object entityOrProxy)
|
||||||
|
*/
|
||||||
|
public boolean isReadOnly();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an associated modifiable proxy to read-only mode, or a read-only
|
||||||
|
* proxy to modifiable mode. If the proxy is currently initialized, its
|
||||||
|
* implementation will be set to the same mode; otherwise, when the
|
||||||
|
* proxy is initialized, its implementation will have the same read-only/
|
||||||
|
* modifiable setting as the proxy. In read-only mode, no snapshot is
|
||||||
|
* maintained and the instance is never dirty checked.
|
||||||
|
*
|
||||||
|
* If the associated proxy already has the specified read-only/modifiable
|
||||||
|
* setting, then this method does nothing.
|
||||||
|
*
|
||||||
|
* @param readOnly, if true, the associated proxy is made read-only;
|
||||||
|
* if false, the associated proxy is made modifiable.
|
||||||
|
* @throws org.hibernate.TransientObjectException if the proxy is not association with a session
|
||||||
|
* @throws org.hibernate.SessionException if the proxy is associated with a sesssion that is closed
|
||||||
|
*
|
||||||
|
* @see org.hibernate.Session#setReadOnly(Object entityOrProxy, boolean readOnly)
|
||||||
|
*/
|
||||||
|
public void setReadOnly(boolean readOnly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the session to which this proxy is associated, or null if it is not attached.
|
* Get the session to which this proxy is associated, or null if it is not attached.
|
||||||
*
|
*
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -67,7 +67,7 @@ public class ReadOnlyTest extends FunctionalTestCase {
|
||||||
return new FunctionalTestClassTestSuite( ReadOnlyTest.class );
|
return new FunctionalTestClassTestSuite( ReadOnlyTest.class );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadOnlyOnProxiesFailureExpected() {
|
public void testReadOnlyOnProxies() {
|
||||||
Session s = openSession();
|
Session s = openSession();
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
s.setCacheMode( CacheMode.IGNORE );
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
@ -82,6 +82,7 @@ public class ReadOnlyTest extends FunctionalTestCase {
|
||||||
|
|
||||||
s = openSession();
|
s = openSession();
|
||||||
s.setCacheMode(CacheMode.IGNORE);
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
s.beginTransaction();
|
||||||
dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpId ) );
|
dp = ( DataPoint ) s.load( DataPoint.class, new Long( dpId ) );
|
||||||
assertFalse( "was initialized", Hibernate.isInitialized( dp ) );
|
assertFalse( "was initialized", Hibernate.isInitialized( dp ) );
|
||||||
s.setReadOnly( dp, true );
|
s.setReadOnly( dp, true );
|
||||||
|
@ -178,6 +179,138 @@ public class ReadOnlyTest extends FunctionalTestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testReadOnlyDelete() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
Transaction t = s.beginTransaction();
|
||||||
|
DataPoint dp = new DataPoint();
|
||||||
|
dp.setX( new BigDecimal(0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
s.save(dp);
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
t = s.beginTransaction();
|
||||||
|
dp = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
|
||||||
|
s.setReadOnly( dp, true );
|
||||||
|
s.delete( dp );
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
t = s.beginTransaction();
|
||||||
|
List list = s.createQuery("from DataPoint where description='done!'").list();
|
||||||
|
assertTrue( list.isEmpty() );
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadOnlyModeWithExistingModifiableEntity() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
Transaction t = s.beginTransaction();
|
||||||
|
DataPoint dp = null;
|
||||||
|
for ( int i=0; i<100; i++ ) {
|
||||||
|
dp = new DataPoint();
|
||||||
|
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
s.save(dp);
|
||||||
|
}
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
t = s.beginTransaction();
|
||||||
|
DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
|
||||||
|
assertFalse( s.isReadOnly( dpLast ) );
|
||||||
|
int i = 0;
|
||||||
|
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
|
||||||
|
.setReadOnly(true)
|
||||||
|
.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
|
int nExpectedChanges = 0;
|
||||||
|
while ( sr.next() ) {
|
||||||
|
dp = (DataPoint) sr.get(0);
|
||||||
|
if ( dp.getId() == dpLast.getId() ) {
|
||||||
|
//dpLast existed in the session before executing the read-only query
|
||||||
|
assertFalse( s.isReadOnly( dp ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertTrue( s.isReadOnly( dp ) );
|
||||||
|
}
|
||||||
|
if (++i==50) {
|
||||||
|
s.setReadOnly(dp, false);
|
||||||
|
nExpectedChanges = ( dp == dpLast ? 1 : 2 );
|
||||||
|
}
|
||||||
|
dp.setDescription("done!");
|
||||||
|
}
|
||||||
|
t.commit();
|
||||||
|
s.clear();
|
||||||
|
t = s.beginTransaction();
|
||||||
|
List list = s.createQuery("from DataPoint where description='done!'").list();
|
||||||
|
assertEquals( list.size(), nExpectedChanges );
|
||||||
|
s.createQuery("delete from DataPoint").executeUpdate();
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModifiableModeWithExistingReadOnlyEntity() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
Transaction t = s.beginTransaction();
|
||||||
|
DataPoint dp = null;
|
||||||
|
for ( int i=0; i<100; i++ ) {
|
||||||
|
dp = new DataPoint();
|
||||||
|
dp.setX( new BigDecimal(i * 0.1d).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale(19, BigDecimal.ROUND_DOWN) );
|
||||||
|
s.save(dp);
|
||||||
|
}
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.setCacheMode(CacheMode.IGNORE);
|
||||||
|
t = s.beginTransaction();
|
||||||
|
DataPoint dpLast = ( DataPoint ) s.get( DataPoint.class, dp.getId() );
|
||||||
|
assertFalse( s.isReadOnly( dpLast ) );
|
||||||
|
s.setReadOnly( dpLast, true );
|
||||||
|
assertTrue( s.isReadOnly( dpLast ) );
|
||||||
|
int i = 0;
|
||||||
|
ScrollableResults sr = s.createQuery("from DataPoint dp order by dp.x asc")
|
||||||
|
.setReadOnly(false)
|
||||||
|
.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
|
int nExpectedChanges = 0;
|
||||||
|
while ( sr.next() ) {
|
||||||
|
dp = (DataPoint) sr.get(0);
|
||||||
|
if ( dp.getId() == dpLast.getId() ) {
|
||||||
|
//dpLast existed in the session before executing the read-only query
|
||||||
|
assertTrue( s.isReadOnly( dp ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertFalse( s.isReadOnly( dp ) );
|
||||||
|
}
|
||||||
|
if (++i==50) {
|
||||||
|
s.setReadOnly(dp, true);
|
||||||
|
nExpectedChanges = ( dp == dpLast ? 99 : 98 );
|
||||||
|
}
|
||||||
|
dp.setDescription("done!");
|
||||||
|
}
|
||||||
|
t.commit();
|
||||||
|
s.clear();
|
||||||
|
t = s.beginTransaction();
|
||||||
|
List list = s.createQuery("from DataPoint where description='done!'").list();
|
||||||
|
assertEquals( list.size(), nExpectedChanges );
|
||||||
|
s.createQuery("delete from DataPoint").executeUpdate();
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
public void testReadOnlyOnTextType() {
|
public void testReadOnlyOnTextType() {
|
||||||
final String origText = "some huge text string";
|
final String origText = "some huge text string";
|
||||||
final String newText = "some even bigger text string";
|
final String newText = "some even bigger text string";
|
||||||
|
|
Loading…
Reference in New Issue