HHH-15001 Hibernate.size(), Hibernate.contains(), Hibernate.get()
add @since tags
This commit is contained in:
parent
3cf6f2e3ef
commit
6c461a3674
|
@ -119,6 +119,68 @@ public final class Hibernate {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the {@linkplain Collection#size() size} of a persistent collection,
|
||||
* without fetching its state from the database.
|
||||
*
|
||||
* @param collection a persistent collection associated with an open session
|
||||
* @return the size of the collection
|
||||
*
|
||||
* @since 6.1.1
|
||||
*/
|
||||
public static int size(Collection<?> collection) {
|
||||
return collection instanceof PersistentCollection
|
||||
? ((PersistentCollection<?>) collection).getSize()
|
||||
: collection.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given persistent collection {@linkplain Collection#contains(Object) contains}
|
||||
* the given element, without fetching its state from the database.
|
||||
*
|
||||
* @param collection a persistent collection associated with an open session
|
||||
* @return true if the collection does contain the given element
|
||||
*
|
||||
* @since 6.1.1
|
||||
*/
|
||||
public static <T> boolean contains(Collection<? super T> collection, T element) {
|
||||
return collection instanceof PersistentCollection
|
||||
? ((PersistentCollection<?>) collection).elementExists(element)
|
||||
: collection.contains(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain 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 value associated by the map with the given key
|
||||
*
|
||||
* @since 6.1.1
|
||||
*/
|
||||
public static <K,V> V get(Map<? super K, V> map, K key) {
|
||||
return map instanceof PersistentCollection
|
||||
? (V) ((PersistentCollection<?>) map).elementByIndex(key)
|
||||
: map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the element of the given persistent list with the given index,
|
||||
* without fetching the state of the list from the database.
|
||||
*
|
||||
* @param list a persistent list associated with an open session
|
||||
* @param key an index belonging to the list
|
||||
* @return the element of the list with the given index
|
||||
*
|
||||
* @since 6.1.1
|
||||
*/
|
||||
public static <T> T get(List<T> list, int key) {
|
||||
return list instanceof PersistentCollection
|
||||
? (T) ((PersistentCollection<?>) list).elementByIndex(key)
|
||||
: list.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the true, underlying class of a proxied persistent class. This operation
|
||||
* will initialize a proxy by side effect.
|
||||
|
@ -225,6 +287,8 @@ public final class Hibernate {
|
|||
* @param id the id of the persistent entity instance
|
||||
*
|
||||
* @return a detached uninitialized proxy
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E createDetachedProxy(SessionFactory sessionFactory, Class<E> entityClass, Object id) {
|
||||
|
@ -242,6 +306,8 @@ public final class Hibernate {
|
|||
* Operations for obtaining references to persistent collections of a certain type.
|
||||
*
|
||||
* @param <C> the type of collection, for example, {@code List<User>}
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static final class CollectionInterface<C> {
|
||||
private final Supplier<C> detached;
|
||||
|
@ -281,6 +347,8 @@ public final class Hibernate {
|
|||
* of a given element type.
|
||||
*
|
||||
* @param <U> the element type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U> CollectionInterface<Collection<U>> bag() {
|
||||
return new CollectionInterface<>(PersistentBag::new, ArrayList::new);
|
||||
|
@ -291,6 +359,8 @@ public final class Hibernate {
|
|||
* of a given element type.
|
||||
*
|
||||
* @param <U> the element type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U> CollectionInterface<Set<U>> set() {
|
||||
return new CollectionInterface<>(PersistentSet::new, HashSet::new);
|
||||
|
@ -301,6 +371,8 @@ public final class Hibernate {
|
|||
* of a given element type.
|
||||
*
|
||||
* @param <U> the element type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U> CollectionInterface<List<U>> list() {
|
||||
return new CollectionInterface<>(PersistentList::new, ArrayList::new);
|
||||
|
@ -312,6 +384,8 @@ public final class Hibernate {
|
|||
*
|
||||
* @param <U> the key type
|
||||
* @param <V> the value type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U,V> CollectionInterface<Map<U,V>> map() {
|
||||
return new CollectionInterface<>(PersistentMap::new, HashMap::new);
|
||||
|
@ -322,6 +396,8 @@ public final class Hibernate {
|
|||
* of a given element type.
|
||||
*
|
||||
* @param <U> the element type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U> CollectionInterface<SortedSet<U>> sortedSet() {
|
||||
return new CollectionInterface<>(PersistentSortedSet::new, TreeSet::new);
|
||||
|
@ -334,6 +410,7 @@ public final class Hibernate {
|
|||
* @param <U> the key type
|
||||
* @param <V> the value type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public static <U,V> CollectionInterface<Map<U,V>> sortedMap() {
|
||||
return new CollectionInterface<>(PersistentSortedMap::new, TreeMap::new);
|
||||
|
@ -344,6 +421,8 @@ public final class Hibernate {
|
|||
* of the given type.
|
||||
*
|
||||
* @param collectionClass the Java class object representing the collection type
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <C> CollectionInterface<C> collection(Class<C> collectionClass) {
|
||||
|
|
|
@ -145,9 +145,10 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
final boolean isExtraLazy = withTemporarySessionIfNeeded(
|
||||
return withTemporarySessionIfNeeded(
|
||||
() -> {
|
||||
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
|
||||
final CollectionEntry entry = session.getPersistenceContextInternal()
|
||||
.getCollectionEntry(this);
|
||||
|
||||
if ( entry != null ) {
|
||||
final CollectionPersister persister = entry.getLoadedPersister();
|
||||
|
@ -162,18 +163,36 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
|||
read();
|
||||
}
|
||||
}
|
||||
else{
|
||||
else {
|
||||
throwLazyInitializationExceptionIfNotConnected();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
return isExtraLazy;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
if ( cachedSize>=0 ) {
|
||||
return cachedSize;
|
||||
}
|
||||
CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry(this);
|
||||
if ( entry == null ) {
|
||||
throwLazyInitializationExceptionIfNotConnected();
|
||||
throwLazyInitializationException("collection not associated with session");
|
||||
throw new AssertionFailure("impossible");
|
||||
}
|
||||
else {
|
||||
if ( hasQueuedOperations() ) {
|
||||
session.flush();
|
||||
}
|
||||
cachedSize = entry.getLoadedPersister().getSize( entry.getLoadedKey(), session );
|
||||
return cachedSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TBH not sure why this is public
|
||||
*
|
||||
|
@ -332,6 +351,22 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean elementExists(Object element) {
|
||||
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
|
||||
if ( entry == null ) {
|
||||
throwLazyInitializationExceptionIfNotConnected();
|
||||
throwLazyInitializationException("collection not associated with session");
|
||||
throw new AssertionFailure("impossible");
|
||||
}
|
||||
else {
|
||||
if ( hasQueuedOperations() ) {
|
||||
session.flush();
|
||||
}
|
||||
return entry.getLoadedPersister().elementExists( entry.getLoadedKey(), element, session );
|
||||
}
|
||||
}
|
||||
|
||||
protected static final Object UNKNOWN = new MarkerObject( "UNKNOWN" );
|
||||
|
||||
protected Object readElementByIndex(final Object index) {
|
||||
|
@ -368,6 +403,22 @@ public abstract class AbstractPersistentCollection<E> implements Serializable, P
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object elementByIndex(Object index) {
|
||||
final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
|
||||
if ( entry == null ) {
|
||||
throwLazyInitializationExceptionIfNotConnected();
|
||||
throwLazyInitializationException("collection not associated with session");
|
||||
throw new AssertionFailure("impossible");
|
||||
}
|
||||
else {
|
||||
if ( hasQueuedOperations() ) {
|
||||
session.flush();
|
||||
}
|
||||
return entry.getLoadedPersister().getElementByIndex( entry.getLoadedKey(), index, session, owner );
|
||||
}
|
||||
}
|
||||
|
||||
protected int getCachedSize() {
|
||||
return cachedSize;
|
||||
}
|
||||
|
|
|
@ -452,6 +452,21 @@ public interface PersistentCollection<E> {
|
|||
*/
|
||||
Collection<E> getOrphans(Serializable snapshot, String entityName);
|
||||
|
||||
/**
|
||||
* Obtain the size of this collection without initializing it
|
||||
*/
|
||||
int getSize();
|
||||
|
||||
/**
|
||||
* Determine if the given element belongs to this collection without initializing it
|
||||
*/
|
||||
boolean elementExists(Object element);
|
||||
|
||||
/**
|
||||
* Obtain the element os this collection associated with the given index without initializing it
|
||||
*/
|
||||
Object elementByIndex(Object index);
|
||||
|
||||
void initializeEmptyCollection(CollectionPersister persister);
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.collection.basic;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
Contact.class, EmailAddress.class, User.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
public class CollectionSizeTest {
|
||||
|
||||
@Test
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
Set<EmailAddress> emailAddresses = new HashSet<>();
|
||||
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
|
||||
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
|
||||
emailAddresses.add( new EmailAddress( "test3@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) );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
user.setContact( contact );
|
||||
session.persist( user );
|
||||
session.persist( contact );
|
||||
session.flush();
|
||||
}
|
||||
);
|
||||
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) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,9 @@
|
|||
package org.hibernate.orm.test.collection.basic;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.CollectionTable;
|
||||
|
@ -17,6 +19,7 @@ import jakarta.persistence.GeneratedValue;
|
|||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
|
@ -26,8 +29,9 @@ public class Contact implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
private Long id;
|
||||
private String name;
|
||||
private Set<EmailAddress> emailAddresses = new HashSet<EmailAddress>();
|
||||
private Set<EmailAddress> emailAddresses2 = new HashSet<EmailAddress>();
|
||||
private Set<EmailAddress> emailAddresses = new HashSet<>();
|
||||
private Set<EmailAddress> emailAddresses2 = new HashSet<>();
|
||||
private Map<EmailAddress,Contact> contactsByEmail = new HashMap<>();
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
|
@ -68,6 +72,16 @@ public class Contact implements Serializable {
|
|||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
@ManyToMany
|
||||
@CollectionTable(name="contact_email_addresses")
|
||||
public Map<EmailAddress, Contact> getContactsByEmail() {
|
||||
return contactsByEmail;
|
||||
}
|
||||
|
||||
public void setContactsByEmail(Map<EmailAddress, Contact> contactsByEmail) {
|
||||
this.contactsByEmail = contactsByEmail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
|
|
Loading…
Reference in New Issue