HHH-15910 Add static remove methods to Hibernate.class

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2022-12-19 21:12:07 +01:00 committed by Jan Schatteman
parent e0f55e5d53
commit d8bf649998
10 changed files with 199 additions and 4 deletions

View File

@ -233,6 +233,57 @@ public final class Hibernate {
: list.get(key);
}
/*
* Remove the value associated with the given key by the given persistent
* map, without fetching the state of the map from the database.
*
* @param map a persistent map associated with an open session
* @param key a key belonging to the map
* @return the previous value associated by the map with the given key, or null if there was no value associated
* with the given key
*
* @since 6.2.0
*/
public static <K, V> V remove(Map<? super K, V> map, K key) {
return ( map instanceof PersistentMap )
? ( (PersistentMap<K, V>) map ).queuedRemove( key )
: map.remove( key );
}
/*
* Remove the specified element of the given persistent set,
* without fetching the state of the set from the database.
*
* @param set a persistent set associated with an open session
* @param element an element belonging to the set
* @return true if this set contained the specified element
*
* @since 6.2.0
*/
public static <T> boolean remove(Set<T> set, T element) {
return ( set instanceof PersistentSet )
? ( (PersistentSet<T>) set ).queuedRemove( element )
: set.remove( element );
}
/*
* Remove the specified element of the given persistent list,
* without fetching the state of the list from the database.
*
* @param list a persistent list associated with an open session
* @param element an element belonging to the list
* @return true if this list contained the specified element
*
* @since 6.2.0
*/
public static <T> boolean remove(List<T> list, T element) {
return ( list instanceof PersistentList )
? ( (PersistentList<T>) list ).queuedRemove( element )
: ( list instanceof PersistentBag )
? ( (PersistentBag<T>) list ).queuedRemove( element )
: list.remove( element );
}
/**
* Get the true, underlying class of a proxied entity. This operation will
* initialize a proxy by side effect.

View File

@ -32,7 +32,8 @@ import java.util.Map;
* <li>Use static methods of {@link org.hibernate.Hibernate},
* for example {@link org.hibernate.Hibernate#size(Collection)},
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
* {@link org.hibernate.Hibernate#get(Map, Object)}, or
* {@link org.hibernate.Hibernate#remove(Map, Object)} instead
* of {@code LazyCollection(EXTRA)}.
* </ul>
*/

View File

@ -26,7 +26,8 @@ import java.util.Map;
* <li>Use static methods of {@link org.hibernate.Hibernate},
* for example {@link org.hibernate.Hibernate#size(Collection)},
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
* {@link org.hibernate.Hibernate#get(Map, Object)}, or
* {@link org.hibernate.Hibernate#remove(Map, Object)} instead
* of {@code LazyCollection(EXTRA)}.
* </ul>
*/

View File

@ -616,7 +616,7 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
);
}
private void throwLazyInitializationExceptionIfNotConnected() {
void throwLazyInitializationExceptionIfNotConnected() {
if ( !isConnectedToSession() ) {
throwLazyInitializationException( "no session or session was closed" );
}
@ -625,7 +625,7 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
}
}
private void throwLazyInitializationException(String message) {
void throwLazyInitializationException(String message) {
throw new LazyInitializationException(
"failed to lazily initialize a collection" +
(role == null ? "" : " of role: " + role) +

View File

@ -18,6 +18,8 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
@ -404,6 +406,27 @@ public class PersistentBag<E> extends AbstractPersistentCollection<E> implements
}
}
@Internal
public boolean queuedRemove(Object element) {
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentBag.this );
if ( entry == null ) {
throwLazyInitializationExceptionIfNotConnected();
throwLazyInitializationException("collection not associated with session");
}
else {
final CollectionPersister persister = entry.getLoadedPersister();
if ( hasQueuedOperations() ) {
getSession().flush();
}
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
elementRemoved = true;
queueOperation( new PersistentBag.SimpleRemove( (E) element ) );
return true;
}
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
read();
@ -633,4 +656,16 @@ public class PersistentBag<E> extends AbstractPersistentCollection<E> implements
bag.add( getAddedInstance() );
}
}
final class SimpleRemove extends AbstractValueDelayedOperation {
public SimpleRemove(E orphan) {
super( null, orphan );
}
@Override
public void operate() {
bag.remove( getOrphan() );
}
}
}

View File

@ -15,6 +15,8 @@ import java.util.ListIterator;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
@ -217,6 +219,27 @@ public class PersistentList<E> extends AbstractPersistentCollection<E> implement
}
}
@Internal
public boolean queuedRemove(Object element) {
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentList.this );
if ( entry == null ) {
throwLazyInitializationExceptionIfNotConnected();
throwLazyInitializationException("collection not associated with session");
}
else {
final CollectionPersister persister = entry.getLoadedPersister();
if ( hasQueuedOperations() ) {
getSession().flush();
}
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
elementRemoved = true;
queueOperation( new PersistentList.SimpleRemove( (E) element ) );
return true;
}
}
return false;
}
@Override
public boolean containsAll(Collection<?> coll) {
read();

View File

@ -15,8 +15,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@ -192,6 +195,28 @@ public class PersistentMap<K,E> extends AbstractPersistentCollection<E> implemen
return map.remove( key );
}
@Internal
public E queuedRemove(Object key) {
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentMap.this );
if ( entry == null ) {
throwLazyInitializationExceptionIfNotConnected();
throwLazyInitializationException("collection not associated with session");
}
else {
final CollectionPersister persister = entry.getLoadedPersister();
if ( hasQueuedOperations() ) {
getSession().flush();
}
Object element = persister.getElementByIndex( entry.getLoadedKey(), key, getSession(), getOwner() );
if ( element != null ) {
elementRemoved = true;
queueOperation( new Remove( (K) key, (E) element ) );
return (E) element;
}
}
return null;
}
@Override
public void putAll(Map<? extends K,? extends E> puts) {
if ( puts.size() > 0 ) {

View File

@ -16,6 +16,8 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@ -223,6 +225,27 @@ public class PersistentSet<E> extends AbstractPersistentCollection<E> implements
}
}
@Internal
public boolean queuedRemove(Object element) {
final CollectionEntry entry = getSession().getPersistenceContextInternal().getCollectionEntry( PersistentSet.this );
if ( entry == null ) {
throwLazyInitializationExceptionIfNotConnected();
throwLazyInitializationException("collection not associated with session");
}
else {
final CollectionPersister persister = entry.getLoadedPersister();
if ( hasQueuedOperations() ) {
getSession().flush();
}
if ( persister.elementExists( entry.getLoadedKey(), element, getSession() ) ) {
elementRemoved = true;
queueOperation( new SimpleRemove( (E) element ) );
return true;
}
}
return false;
}
@Override
public boolean containsAll(Collection<?> coll) {
read();

View File

@ -12,7 +12,9 @@ import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -35,12 +37,16 @@ public class CollectionSizeTest {
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
emailAddresses.add( new EmailAddress( "test3@test.com" ) );
List<EmailAddress> emailAddresses3 = new ArrayList<>();
emailAddresses3.add( new EmailAddress( "test4@test.com" ) );
emailAddresses3.add( new EmailAddress( "test5@test.com" ) );
User user = new User();
user.setName( "john" );
Contact contact = new Contact();
contact.setName( "John Doe" );
contact.setEmailAddresses( emailAddresses );
emailAddresses.forEach( address -> contact.getContactsByEmail().put(address, contact) );
contact.setEmailAddresses3( emailAddresses3 );
scope.inTransaction(
session -> {
@ -53,15 +59,31 @@ public class CollectionSizeTest {
scope.inTransaction(
session -> {
Contact cont = session.get(Contact.class, contact.getId());
Set<EmailAddress> addresses = cont.getEmailAddresses();
assertEquals( Hibernate.size(addresses), 3 );
assertTrue( Hibernate.contains( addresses, new EmailAddress( "test1@test.com" ) ) );
assertFalse( Hibernate.contains( addresses, new EmailAddress( "test9@test.com" ) ) );
assertFalse( Hibernate.isInitialized(addresses) );
Map<EmailAddress, Contact> contactsByEmail = cont.getContactsByEmail();
assertEquals( cont, Hibernate.get(contactsByEmail, new EmailAddress( "test1@test.com" ) ) );
assertNull( Hibernate.get(contactsByEmail, new EmailAddress( "test9@test.com" ) ) );
assertFalse( Hibernate.isInitialized(contactsByEmail) );
Hibernate.remove( contactsByEmail, new EmailAddress( "test1@test.com" ) );
assertFalse( Hibernate.isInitialized(contactsByEmail) );
assertEquals( cont, Hibernate.get(contactsByEmail, new EmailAddress( "test1@test.com" ) ) );
assertEquals( Hibernate.size( contactsByEmail.entrySet() ), 3 );
Hibernate.remove( addresses, new EmailAddress( "test1@test.com" ) );
assertFalse( Hibernate.isInitialized(addresses) );
assertEquals( Hibernate.size( addresses ), 3 );
List<EmailAddress> addresses3 = cont.getEmailAddresses3();
Hibernate.remove( addresses3, new EmailAddress( "test4@test.com" ) );
assertFalse( Hibernate.isInitialized( addresses3 ) );
assertEquals( Hibernate.size(addresses3), 2 );
}
);
}

View File

@ -7,8 +7,10 @@
package org.hibernate.orm.test.collection.basic;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jakarta.persistence.Basic;
@ -31,6 +33,8 @@ public class Contact implements Serializable {
private String name;
private Set<EmailAddress> emailAddresses = new HashSet<>();
private Set<EmailAddress> emailAddresses2 = new HashSet<>();
private List<EmailAddress> emailAddresses3 = new ArrayList<>();
private Map<EmailAddress,Contact> contactsByEmail = new HashMap<>();
@Id
@ -52,6 +56,16 @@ public class Contact implements Serializable {
this.name = name;
}
@ElementCollection
@CollectionTable(name = "user_email_addresses3", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
public List<EmailAddress> getEmailAddresses3() {
return emailAddresses3;
}
public void setEmailAddresses3(List<EmailAddress> emailAddresses3) {
this.emailAddresses3 = emailAddresses3;
}
@ElementCollection
@CollectionTable(name = "user_email_addresses2", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
public Set<EmailAddress> getEmailAddresses2() {