HHH-2879 - create a SimpleNaturalIdLoadAccess for easier access for simple (single attribute) natural ids
This commit is contained in:
parent
f6c4868a44
commit
3071fa892f
|
@ -824,6 +824,32 @@ public interface Session extends SharedSessionContract {
|
|||
*/
|
||||
public NaturalIdLoadAccess byNaturalId(Class entityClass);
|
||||
|
||||
/**
|
||||
* Create an {@link SimpleNaturalIdLoadAccess} instance to retrieve the specified entity by
|
||||
* its natural id.
|
||||
*
|
||||
* @param entityName The entity name of the entity type to be retrieved
|
||||
*
|
||||
* @return load delegate for loading the specified entity type by natural id
|
||||
*
|
||||
* @throws HibernateException If the specified entityClass cannot be resolved as a mapped entity, or if the
|
||||
* entity does not define a natural-id or if its natural-id is made up of multiple attributes.
|
||||
*/
|
||||
public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName);
|
||||
|
||||
/**
|
||||
* Create an {@link SimpleNaturalIdLoadAccess} instance to retrieve the specified entity by
|
||||
* its simple (single attribute) natural id.
|
||||
*
|
||||
* @param entityClass The entity type to be retrieved
|
||||
*
|
||||
* @return load delegate for loading the specified entity type by natural id
|
||||
*
|
||||
* @throws HibernateException If the specified entityClass cannot be resolved as a mapped entity, or if the
|
||||
* entity does not define a natural-id or if its natural-id is made up of multiple attributes.
|
||||
*/
|
||||
public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass);
|
||||
|
||||
/**
|
||||
* Enable the named filter for this current session.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate;
|
||||
|
||||
/**
|
||||
* Loads an entity by its natural identifier
|
||||
*
|
||||
* @author Eric Dalquist
|
||||
* @author Steve Ebersole
|
||||
*
|
||||
* @see org.hibernate.annotations.NaturalId
|
||||
* @see NaturalIdLoadAccess
|
||||
*/
|
||||
public interface SimpleNaturalIdLoadAccess {
|
||||
/**
|
||||
* Specify the {@link org.hibernate.LockOptions} to use when retrieving the entity.
|
||||
*
|
||||
* @param lockOptions The lock options to use.
|
||||
*
|
||||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
public SimpleNaturalIdLoadAccess with(LockOptions lockOptions);
|
||||
|
||||
/**
|
||||
* Return the persistent instance with the given natural id value, assuming that the instance exists. This method
|
||||
* might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
|
||||
*
|
||||
* You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
|
||||
* instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
|
||||
* actual error.
|
||||
*
|
||||
* @param naturalIdValue The value of the natural-id for the entity to retrieve
|
||||
*
|
||||
* @return the persistent instance or proxy
|
||||
*/
|
||||
public Object getReference(Object naturalIdValue);
|
||||
|
||||
/**
|
||||
* Return the persistent instance with the given natural id value, or {@code null} if there is no such persistent
|
||||
* instance. If the instance is already associated with the session, return that instance, initializing it if
|
||||
* needed. This method never returns an uninitialized instance.
|
||||
*
|
||||
* @param naturalIdValue The value of the natural-id for the entity to retrieve
|
||||
*
|
||||
* @return The persistent instance or {@code null}
|
||||
*/
|
||||
public Object load(Object naturalIdValue);
|
||||
|
||||
}
|
|
@ -71,6 +71,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.SessionBuilder;
|
||||
import org.hibernate.SessionException;
|
||||
import org.hibernate.SharedSessionBuilder;
|
||||
import org.hibernate.SimpleNaturalIdLoadAccess;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.TypeHelper;
|
||||
|
@ -946,6 +947,16 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
return new NaturalIdLoadAccessImpl( entityClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) {
|
||||
return new SimpleNaturalIdLoadAccessImpl( entityName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass) {
|
||||
return new SimpleNaturalIdLoadAccessImpl( entityClass );
|
||||
}
|
||||
|
||||
private void fireLoad(LoadEvent event, LoadType loadType) {
|
||||
errorIfClosed();
|
||||
checkTransactionSynchStatus();
|
||||
|
@ -975,7 +986,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
}
|
||||
|
||||
public void refresh(Object object, LockMode lockMode) throws HibernateException {
|
||||
fireRefresh( new RefreshEvent(object, lockMode, this) );
|
||||
fireRefresh( new RefreshEvent( object, lockMode, this ) );
|
||||
}
|
||||
|
||||
public void refresh(Object object, LockOptions lockOptions) throws HibernateException {
|
||||
|
@ -1735,7 +1746,7 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
public void setReadOnly(Object entity, boolean readOnly) {
|
||||
errorIfClosed();
|
||||
checkTransactionSynchStatus();
|
||||
persistenceContext.setReadOnly(entity, readOnly);
|
||||
persistenceContext.setReadOnly( entity, readOnly );
|
||||
}
|
||||
|
||||
public void doWork(final Work work) throws HibernateException {
|
||||
|
@ -2171,20 +2182,23 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
fireLock( object, lockOptions );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class IdentifierLoadAccessImpl implements IdentifierLoadAccess {
|
||||
private final EntityPersister entityPersister;
|
||||
private LockOptions lockOptions;
|
||||
|
||||
private IdentifierLoadAccessImpl(EntityPersister entityPersister) {
|
||||
this.entityPersister = entityPersister;
|
||||
|
||||
if ( ! entityPersister.hasNaturalIdentifier() ) {
|
||||
throw new HibernateException(
|
||||
String.format( "Entity [%s] did not define a natural id", entityPersister.getEntityName() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private IdentifierLoadAccessImpl(String entityName) {
|
||||
this( factory.getEntityPersister( entityName ) );
|
||||
if ( entityPersister == null ) {
|
||||
throw new HibernateException( "Unable to locate persister: " + entityName );
|
||||
}
|
||||
this( locateEntityPersister( entityName ) );
|
||||
}
|
||||
|
||||
private IdentifierLoadAccessImpl(Class entityClass) {
|
||||
|
@ -2241,6 +2255,14 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
}
|
||||
}
|
||||
|
||||
private EntityPersister locateEntityPersister(String entityName) {
|
||||
final EntityPersister entityPersister = factory.getEntityPersister( entityName );
|
||||
if ( entityPersister == null ) {
|
||||
throw new HibernateException( "Unable to locate persister: " + entityName );
|
||||
}
|
||||
return entityPersister;
|
||||
}
|
||||
|
||||
private class NaturalIdLoadAccessImpl implements NaturalIdLoadAccess {
|
||||
private final EntityPersister entityPersister;
|
||||
private final Map<String, Object> naturalIdParameters = new LinkedHashMap<String, Object>();
|
||||
|
@ -2248,13 +2270,16 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
|
||||
private NaturalIdLoadAccessImpl(EntityPersister entityPersister) {
|
||||
this.entityPersister = entityPersister;
|
||||
|
||||
if ( ! entityPersister.hasNaturalIdentifier() ) {
|
||||
throw new HibernateException(
|
||||
String.format( "Entity [%s] did not define a natural id", entityPersister.getEntityName() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private NaturalIdLoadAccessImpl(String entityName) {
|
||||
this( factory.getEntityPersister( entityName ) );
|
||||
if ( entityPersister == null ) {
|
||||
throw new HibernateException( "Unable to locate persister: " + entityName );
|
||||
}
|
||||
this( locateEntityPersister( entityName ) );
|
||||
}
|
||||
|
||||
private NaturalIdLoadAccessImpl(Class entityClass) {
|
||||
|
@ -2306,4 +2331,77 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
return this.getIdentifierLoadAccess().load( entityId );
|
||||
}
|
||||
}
|
||||
|
||||
private class SimpleNaturalIdLoadAccessImpl implements SimpleNaturalIdLoadAccess {
|
||||
private final EntityPersister entityPersister;
|
||||
private final String naturalIdAttributeName;
|
||||
private LockOptions lockOptions;
|
||||
|
||||
private SimpleNaturalIdLoadAccessImpl(EntityPersister entityPersister) {
|
||||
this.entityPersister = entityPersister;
|
||||
|
||||
if ( ! entityPersister.hasNaturalIdentifier() ) {
|
||||
throw new HibernateException(
|
||||
String.format( "Entity [%s] did not define a natural id", entityPersister.getEntityName() )
|
||||
);
|
||||
}
|
||||
|
||||
if ( entityPersister.getNaturalIdentifierProperties().length != 1 ) {
|
||||
throw new HibernateException(
|
||||
String.format( "Entity [%s] did not define a simple natural id", entityPersister.getEntityName() )
|
||||
);
|
||||
}
|
||||
|
||||
final int naturalIdAttributePosition = entityPersister.getNaturalIdentifierProperties()[0];
|
||||
this.naturalIdAttributeName = entityPersister.getPropertyNames()[ naturalIdAttributePosition ];
|
||||
}
|
||||
|
||||
private SimpleNaturalIdLoadAccessImpl(String entityName) {
|
||||
this( locateEntityPersister( entityName ) );
|
||||
}
|
||||
|
||||
private SimpleNaturalIdLoadAccessImpl(Class entityClass) {
|
||||
this( entityClass.getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SimpleNaturalIdLoadAccessImpl with(LockOptions lockOptions) {
|
||||
this.lockOptions = lockOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getReference(Object naturalIdValue) {
|
||||
final Serializable entityId = resolveNaturalId( naturalIdValue );
|
||||
if ( entityId == null ) {
|
||||
return null;
|
||||
}
|
||||
return this.getIdentifierLoadAccess().getReference( entityId );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object load(Object naturalIdValue) {
|
||||
final Serializable entityId = resolveNaturalId( naturalIdValue );
|
||||
if ( entityId == null ) {
|
||||
return null;
|
||||
}
|
||||
return this.getIdentifierLoadAccess().load( entityId );
|
||||
}
|
||||
|
||||
private Serializable resolveNaturalId(Object naturalIdValue) {
|
||||
final Map<String,Object> naturalIdValueMap = Collections.singletonMap( naturalIdAttributeName, naturalIdValue );
|
||||
final ResolveNaturalIdEvent event =
|
||||
new ResolveNaturalIdEvent( naturalIdValueMap, entityPersister, SessionImpl.this );
|
||||
fireResolveNaturalId( event );
|
||||
return event.getEntityId();
|
||||
}
|
||||
|
||||
private IdentifierLoadAccess getIdentifierLoadAccess() {
|
||||
final IdentifierLoadAccessImpl identifierLoadAccess = new IdentifierLoadAccessImpl( entityPersister );
|
||||
if ( this.lockOptions != null ) {
|
||||
identifierLoadAccess.with( lockOptions );
|
||||
}
|
||||
return identifierLoadAccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ import org.hibernate.test.jpa.AbstractJPATest;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
@ -106,6 +108,31 @@ public class ImmutableNaturalIdTest extends AbstractJPATest {
|
|||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNaturalIdLoadAccessCache() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
User u = new User( "steve", "superSecret" );
|
||||
s.persist( u );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
u = (User) s.bySimpleNaturalId( User.class ).load( "steve" );
|
||||
assertNotNull( u );
|
||||
User u2 = (User) s.bySimpleNaturalId( User.class ).getReference( "steve" );
|
||||
assertTrue( u == u2 );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete User" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNaturalIdLoadAccessCache() {
|
||||
Session s = openSession();
|
||||
|
|
Loading…
Reference in New Issue