HHH-4910 The collection cache is evicted if a related collection element is inserted, removed or updated
HHH-4910 minor fixes HHH-4910 make this feature configurable
This commit is contained in:
parent
66b222c8bf
commit
bcd6185809
170
hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java
vendored
Normal file
170
hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.cache.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.cache.spi.CacheKey;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.EventType;
|
||||
import org.hibernate.event.spi.PostDeleteEvent;
|
||||
import org.hibernate.event.spi.PostDeleteEventListener;
|
||||
import org.hibernate.event.spi.PostInsertEvent;
|
||||
import org.hibernate.event.spi.PostInsertEventListener;
|
||||
import org.hibernate.event.spi.PostUpdateEvent;
|
||||
import org.hibernate.event.spi.PostUpdateEventListener;
|
||||
import org.hibernate.integrator.spi.Integrator;
|
||||
import org.hibernate.metamodel.source.MetadataImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger (latest modification by $Author$)
|
||||
* @version $Id$
|
||||
* @created 30.08.13 - 01:54
|
||||
*/
|
||||
public class CollectionCacheInvalidator implements Integrator,
|
||||
PostInsertEventListener,
|
||||
PostDeleteEventListener,
|
||||
PostUpdateEventListener {
|
||||
private static final Logger LOG = Logger.getLogger( CollectionCacheInvalidator.class.getName() );
|
||||
|
||||
@Override
|
||||
public void integrate(
|
||||
Configuration configuration,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry) {
|
||||
integrate( serviceRegistry, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void integrate(
|
||||
MetadataImplementor metadata,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry) {
|
||||
integrate( serviceRegistry, sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disintegrate(
|
||||
SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostInsert(PostInsertEvent event) {
|
||||
evictCache( event.getEntity(), event.getPersister(), event.getSession(), null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresPostCommitHanding(EntityPersister persister) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostDelete(PostDeleteEvent event) {
|
||||
evictCache( event.getEntity(), event.getPersister(), event.getSession(), null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostUpdate(PostUpdateEvent event) {
|
||||
evictCache( event.getEntity(), event.getPersister(), event.getSession(), event.getOldState() );
|
||||
}
|
||||
|
||||
private void integrate(SessionFactoryServiceRegistry serviceRegistry, SessionFactoryImplementor sessionFactory) {
|
||||
if ( !sessionFactory.getSettings().isAutoEvictCollectionCache() ) {
|
||||
// feature is disabled
|
||||
return;
|
||||
}
|
||||
if ( !sessionFactory.getSettings().isSecondLevelCacheEnabled() ) {
|
||||
// Nothing to do, if caching is disabled
|
||||
return;
|
||||
}
|
||||
EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
||||
eventListenerRegistry.appendListeners( EventType.POST_INSERT, this );
|
||||
eventListenerRegistry.appendListeners( EventType.POST_DELETE, this );
|
||||
eventListenerRegistry.appendListeners( EventType.POST_UPDATE, this );
|
||||
}
|
||||
|
||||
private void evictCache(Object entity, EntityPersister persister, EventSource session, Object[] oldState) {
|
||||
try {
|
||||
SessionFactoryImplementor factory = persister.getFactory();
|
||||
|
||||
Set<String> collectionRoles = factory.getCollectionRolesByEntityParticipant( persister.getEntityName() );
|
||||
if ( collectionRoles == null || collectionRoles.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
for ( String role : collectionRoles ) {
|
||||
CollectionPersister collectionPersister = factory.getCollectionPersister( role );
|
||||
if ( !collectionPersister.hasCache() ) {
|
||||
// ignore collection if no caching is used
|
||||
continue;
|
||||
}
|
||||
// this is the property this OneToMany relation is mapped by
|
||||
String mappedBy = collectionPersister.getMappedByProperty();
|
||||
if ( mappedBy != null ) {
|
||||
int i = persister.getEntityMetamodel().getPropertyIndex( mappedBy );
|
||||
Serializable oldId = null;
|
||||
if ( oldState != null ) {
|
||||
// in case of updating an entity we perhaps have to decache 2 entity collections, this is the old one
|
||||
oldId = session.getIdentifier( oldState[i] );
|
||||
}
|
||||
Object ref = persister.getPropertyValue( entity, i );
|
||||
Serializable id = null;
|
||||
if ( ref != null ) {
|
||||
id = session.getIdentifier( ref );
|
||||
}
|
||||
// only evict if the related entity has changed
|
||||
if ( id != null && !id.equals( oldId ) ) {
|
||||
evict( id, collectionPersister, session );
|
||||
if ( oldId != null ) {
|
||||
evict( oldId, collectionPersister, session );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG.debug( "Evict CollectionRegion " + role );
|
||||
collectionPersister.getCacheAccessStrategy().evictAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
//don't let decaching influence other logic
|
||||
LOG.error( "", e );
|
||||
}
|
||||
}
|
||||
|
||||
private void evict(Serializable id, CollectionPersister collectionPersister, EventSource session) {
|
||||
LOG.debug( "Evict CollectionRegion " + collectionPersister.getRole() + " for id " + id );
|
||||
CacheKey key = session.generateCacheKey( id, collectionPersister.getKeyType(), collectionPersister.getRole() );
|
||||
collectionPersister.getCacheAccessStrategy().evict( key );
|
||||
}
|
||||
}
|
|
@ -325,7 +325,10 @@ public interface AvailableSettings {
|
|||
* Enable use of structured second-level cache entries
|
||||
*/
|
||||
public static final String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries";
|
||||
|
||||
/**
|
||||
* Enables the eviction of the OneToMany-Site-Cache of a bi-directional association, when the ManyToOne site changes
|
||||
*/
|
||||
public static final String AUTO_EVICT_COLLECTION_CACHE = "hibernate.cache.auto_evict_collection_cache";
|
||||
/**
|
||||
* Enable statistics collection
|
||||
*/
|
||||
|
|
|
@ -62,6 +62,7 @@ public final class Settings {
|
|||
private boolean queryCacheEnabled;
|
||||
private boolean structuredCacheEntriesEnabled;
|
||||
private boolean secondLevelCacheEnabled;
|
||||
private boolean autoEvictCollectionCache;
|
||||
private String cacheRegionPrefix;
|
||||
private boolean minimalPutsEnabled;
|
||||
private boolean commentsEnabled;
|
||||
|
@ -518,4 +519,12 @@ public final class Settings {
|
|||
public void setJtaTrackByThread(boolean jtaTrackByThread) {
|
||||
this.jtaTrackByThread = jtaTrackByThread;
|
||||
}
|
||||
|
||||
public boolean isAutoEvictCollectionCache() {
|
||||
return autoEvictCollectionCache;
|
||||
}
|
||||
|
||||
public void setAutoEvictCollectionCache(boolean autoEvictCollectionCache) {
|
||||
this.autoEvictCollectionCache = autoEvictCollectionCache;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,6 +325,12 @@ public class SettingsFactory implements Serializable {
|
|||
}
|
||||
settings.setDirectReferenceCacheEntriesEnabled( useDirectReferenceCacheEntries );
|
||||
|
||||
boolean autoEvictCollectionCache = ConfigurationHelper.getBoolean( AvailableSettings.AUTO_EVICT_COLLECTION_CACHE, properties, false);
|
||||
if ( debugEnabled ) {
|
||||
LOG.debugf( "Automatic eviction of collection cache: %s", enabledDisabled(autoEvictCollectionCache) );
|
||||
}
|
||||
settings.setAutoEvictCollectionCache( autoEvictCollectionCache );
|
||||
|
||||
//Statistics and logging:
|
||||
|
||||
boolean useStatistics = ConfigurationHelper.getBoolean( AvailableSettings.GENERATE_STATISTICS, properties );
|
||||
|
|
|
@ -398,6 +398,7 @@ public abstract class CollectionBinder {
|
|||
LOG.debugf( "Collection role: %s", role );
|
||||
collection.setRole( role );
|
||||
collection.setNodeName( propertyName );
|
||||
collection.setMappedByProperty( mappedBy );
|
||||
|
||||
if ( property.isAnnotationPresent( MapKeyColumn.class )
|
||||
&& mapKeyPropertyName != null ) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.LinkedHashSet;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.cache.internal.CollectionCacheInvalidator;
|
||||
import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator;
|
||||
import org.hibernate.integrator.spi.Integrator;
|
||||
import org.hibernate.integrator.spi.IntegratorService;
|
||||
|
@ -46,6 +47,7 @@ public class IntegratorServiceImpl implements IntegratorService {
|
|||
// separate project/jars.
|
||||
addIntegrator( new BeanValidationIntegrator() );
|
||||
addIntegrator( new JaccIntegrator() );
|
||||
addIntegrator( new CollectionCacheInvalidator() );
|
||||
|
||||
// register provided integrators
|
||||
for ( Integrator integrator : providedIntegrators ) {
|
||||
|
|
|
@ -72,6 +72,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
private String referencedPropertyName;
|
||||
private String nodeName;
|
||||
private String elementNodeName;
|
||||
private String mappedByProperty;
|
||||
private boolean sorted;
|
||||
private Comparator comparator;
|
||||
private String comparatorClassName;
|
||||
|
@ -667,4 +668,12 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
public String getComparatorClassName() {
|
||||
return comparatorClassName;
|
||||
}
|
||||
|
||||
public String getMappedByProperty() {
|
||||
return mappedByProperty;
|
||||
}
|
||||
|
||||
public void setMappedByProperty(String mappedByProperty) {
|
||||
this.mappedByProperty = mappedByProperty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ import org.jboss.logging.Logger;
|
|||
|
||||
/**
|
||||
* Base implementation of the <tt>QueryableCollection</tt> interface.
|
||||
*
|
||||
*
|
||||
* @author Gavin King
|
||||
* @see BasicCollectionPersister
|
||||
* @see OneToManyPersister
|
||||
|
@ -149,6 +149,7 @@ public abstract class AbstractCollectionPersister
|
|||
private final String nodeName;
|
||||
private final String elementNodeName;
|
||||
private final String indexNodeName;
|
||||
private String mappedByProperty;
|
||||
|
||||
protected final boolean indexContainsFormula;
|
||||
protected final boolean elementIsPureFormula;
|
||||
|
@ -266,6 +267,7 @@ public abstract class AbstractCollectionPersister
|
|||
queryLoaderName = collection.getLoaderName();
|
||||
nodeName = collection.getNodeName();
|
||||
isMutable = collection.isMutable();
|
||||
mappedByProperty = collection.getMappedByProperty();
|
||||
|
||||
Table table = collection.getCollectionTable();
|
||||
fetchMode = collection.getElement().getFetchMode();
|
||||
|
@ -1642,14 +1644,14 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
protected abstract int doUpdateRows(Serializable key, PersistentCollection collection, SessionImplementor session)
|
||||
throws HibernateException;
|
||||
|
||||
|
||||
public void processQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session)
|
||||
throws HibernateException {
|
||||
if ( collection.hasQueuedOperations() ) {
|
||||
doProcessQueuedOps( collection, key, session );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected abstract void doProcessQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session)
|
||||
throws HibernateException;
|
||||
|
||||
|
@ -1923,7 +1925,7 @@ public abstract class AbstractCollectionPersister
|
|||
/**
|
||||
* Intended for internal use only. In fact really only currently used from
|
||||
* test suite for assertion purposes.
|
||||
*
|
||||
*
|
||||
* @return The default collection initializer for this persister/collection.
|
||||
*/
|
||||
public CollectionInitializer getInitializer() {
|
||||
|
@ -1934,6 +1936,10 @@ public abstract class AbstractCollectionPersister
|
|||
return batchSize;
|
||||
}
|
||||
|
||||
public String getMappedByProperty() {
|
||||
return mappedByProperty;
|
||||
}
|
||||
|
||||
private class StandardOrderByAliasResolver implements OrderByAliasResolver {
|
||||
private final String rootAlias;
|
||||
|
||||
|
@ -1952,7 +1958,7 @@ public abstract class AbstractCollectionPersister
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract FilterAliasGenerator getFilterAliasGenerator(final String rootAlias);
|
||||
|
||||
// ColectionDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -319,4 +319,9 @@ public interface CollectionPersister extends CollectionDefinition {
|
|||
public boolean elementExists(Serializable key, Object element, SessionImplementor session);
|
||||
public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner);
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* @return the Name of the Property, this collection is mapped by
|
||||
*/
|
||||
public String getMappedByProperty();
|
||||
}
|
||||
|
|
180
hibernate-core/src/test/java/org/hibernate/cache/CollectionCacheEvictionTest.java
vendored
Normal file
180
hibernate-core/src/test/java/org/hibernate/cache/CollectionCacheEvictionTest.java
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.test.cache;
|
||||
|
||||
import org.hibernate.ObjectNotFoundException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-4910")
|
||||
public class CollectionCacheEvictionTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {User.class, Company.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.AUTO_EVICT_COLLECTION_CACHE, "true" );
|
||||
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
|
||||
cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
|
||||
cfg.setProperty( Environment.CACHE_PROVIDER_CONFIG, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Company company1 = new Company( 1 );
|
||||
s.save( company1 );
|
||||
|
||||
User user = new User( 1, company1 );
|
||||
s.save( user );
|
||||
|
||||
Company company2 = new Company( 2 );
|
||||
s.save( company2 );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTest() throws Exception {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
s.createQuery( "delete from org.hibernate.test.cache.User" ).executeUpdate();
|
||||
s.createQuery( "delete from org.hibernate.test.cache.Company" ).executeUpdate();
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionCacheEvictionInsert() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Company company = (Company) s.get( Company.class, 1 );
|
||||
// init cache of collection
|
||||
assertEquals( 1, company.getUsers().size() );
|
||||
|
||||
User user = new User( 2, company );
|
||||
s.save( user );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
company = (Company) s.get( Company.class, 1 );
|
||||
// fails if cache is not evicted
|
||||
assertEquals( 2, company.getUsers().size() );
|
||||
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionCacheEvictionRemove() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Company company = (Company) s.get( Company.class, 1 );
|
||||
// init cache of collection
|
||||
assertEquals( 1, company.getUsers().size() );
|
||||
|
||||
s.delete( company.getUsers().get( 0 ) );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
company = (Company) s.get( Company.class, 1 );
|
||||
// fails if cache is not evicted
|
||||
try {
|
||||
assertEquals( 0, company.getUsers().size() );
|
||||
}
|
||||
catch (ObjectNotFoundException e) {
|
||||
fail( "Cached element not found" );
|
||||
}
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionCacheEvictionUpdate() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Company company1 = (Company) s.get( Company.class, 1 );
|
||||
Company company2 = (Company) s.get( Company.class, 2 );
|
||||
|
||||
// init cache of collection
|
||||
assertEquals( 1, company1.getUsers().size() );
|
||||
assertEquals( 0, company2.getUsers().size() );
|
||||
|
||||
User user = (User) s.get( User.class, 1 );
|
||||
user.setCompany( company2 );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
company1 = (Company) s.get( Company.class, 1 );
|
||||
company2 = (Company) s.get( Company.class, 2 );
|
||||
|
||||
assertEquals( 1, company2.getUsers().size() );
|
||||
|
||||
// fails if cache is not evicted
|
||||
try {
|
||||
assertEquals( 0, company1.getUsers().size() );
|
||||
}
|
||||
catch (ObjectNotFoundException e) {
|
||||
fail( "Cached element not found" );
|
||||
}
|
||||
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.test.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
@Entity
|
||||
public class Company {
|
||||
@Id
|
||||
int id;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||
List<User> users = new ArrayList<User>();
|
||||
|
||||
public Company() {
|
||||
}
|
||||
|
||||
public Company(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(List<User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.test.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class User {
|
||||
@Id
|
||||
int id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
Company company;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public User(int id, Company company) {
|
||||
this.id = id;
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Company getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(Company group) {
|
||||
this.company = group;
|
||||
}
|
||||
}
|
|
@ -850,6 +850,11 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappedByProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQueuedOps(PersistentCollection collection, Serializable key, SessionImplementor session)
|
||||
throws HibernateException {
|
||||
|
|
Loading…
Reference in New Issue