Skip to content

Commit 526e282

Browse files
committed
HHH-17948 add Session.findAll(), StatelessSession.getAll()
Signed-off-by: Gavin King <[email protected]>
1 parent 250a59a commit 526e282

File tree

9 files changed

+175
-4
lines changed

9 files changed

+175
-4
lines changed

hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ default MultiIdentifierLoadAccess<T> with(RootGraph<T> graph) {
126126

127127
/**
128128
* Should {@link #multiLoad} return entity instances that have been
129-
* {@link Session#remove(Object) marked for removal} in the current
130-
* session, but not yet {@code delete}d in the database?
129+
* {@linkplain Session#remove(Object) marked for removal} in the
130+
* current session, but not yet {@code delete}d in the database?
131131
* <p>
132132
* By default, instances marked for removal are replaced by null in
133133
* the returned list of entities when {@link #enableOrderedReturn}

hibernate-core/src/main/java/org/hibernate/Session.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,26 @@ public interface Session extends SharedSessionContract, EntityManager {
691691
*/
692692
void clear();
693693

694+
/**
695+
* Return the persistent instances of the given entity class with the given identifiers
696+
* as a list. The position of an instance in the list matches the position of its identifier
697+
* in the given array, and the list contains a null value if there is no persistent instance
698+
* matching a given identifier. If an instance is already associated with the session, that
699+
* instance is returned. This method never returns an uninitialized instance.
700+
* <p>
701+
* Every object returned by {@code findAll()} is either an unproxied instance of the given
702+
* entity class, or a fully-fetched proxy object.
703+
*
704+
* @param entityType the entity type
705+
* @param ids the identifiers
706+
*
707+
* @return an ordered list of persistent instances, with null elements representing missing
708+
* entities
709+
*
710+
* @since 6.5
711+
*/
712+
<E> List<E> findAll(Class<E> entityType, Object... ids);
713+
694714
/**
695715
* Return the persistent instance of the given entity class with the given identifier,
696716
* or null if there is no such persistent instance. If the instance is already associated
@@ -699,8 +719,8 @@ public interface Session extends SharedSessionContract, EntityManager {
699719
* <p>
700720
* This operation is very similar to {@link #find(Class, Object)}.
701721
* <p>
702-
* The object returned by {@code get()} or {@code find() } is either an unproxied instance
703-
* of the given entity class, of a fully-fetched proxy object.
722+
* The object returned by {@code get()} or {@code find()} is either an unproxied instance
723+
* of the given entity class, or a fully-fetched proxy object.
704724
* <p>
705725
* This operation requests {@link LockMode#NONE}, that is, no lock, allowing the object
706726
* to be retrieved from the cache without the cost of database access. However, if it is

hibernate-core/src/main/java/org/hibernate/StatelessSession.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import jakarta.persistence.EntityGraph;
1010
import org.hibernate.graph.GraphSemantic;
1111

12+
import java.util.List;
13+
1214
/**
1315
* A command-oriented API often used for performing bulk operations against
1416
* the database. A stateless session has no persistence context, and always
@@ -250,6 +252,23 @@ public interface StatelessSession extends SharedSessionContract {
250252
*/
251253
<T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id, LockMode lockMode);
252254

255+
/**
256+
* Retrieve multiple rows, returning entity instances in a
257+
* list where the position of an instance in the list matches
258+
* the position of its identifier in the given array, and the
259+
* list contains a null value if there is no persistent
260+
* instance matching a given identifier.
261+
*
262+
* @param entityClass The class of the entity to retrieve
263+
* @param ids The ids of the entities to retrieve
264+
*
265+
* @return an ordered list of detached entity instances, with
266+
* null elements representing missing entities
267+
*
268+
* @since 6.5
269+
*/
270+
<T> List<T> getAll(Class<T> entityClass, Object... ids);
271+
253272
/**
254273
* Refresh the entity instance state from the database.
255274
*

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,11 @@ public void detach(Object entity) {
953953
delegate.detach( entity );
954954
}
955955

956+
@Override
957+
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
958+
return delegate.findAll( entityType, ids );
959+
}
960+
956961
@Override
957962
public <T> T get(Class<T> theClass, Object id) {
958963
return delegate.get( theClass, id );

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ public void clear() {
263263
this.lazySession.get().clear();
264264
}
265265

266+
@Override
267+
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
268+
return this.lazySession.get().findAll( entityType, ids );
269+
}
270+
266271
@Override
267272
public <T> T get(Class<T> entityType, Object id) {
268273
return this.lazySession.get().get( entityType, id );

hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.sql.NClob;
2020
import java.sql.SQLException;
2121
import java.util.HashMap;
22+
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Set;
2425
import java.util.TimeZone;
@@ -946,6 +947,11 @@ public Object load(String entityName, Object id) throws HibernateException {
946947
return this.byId( entityName ).getReference( id );
947948
}
948949

950+
@Override
951+
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
952+
return this.byMultipleIds( entityType ).multiLoad( ids );
953+
}
954+
949955
@Override
950956
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
951957
return this.byId( entityClass ).load( id );

hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
*/
77
package org.hibernate.internal;
88

9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
import java.util.List;
912
import java.util.Set;
1013
import java.util.function.BiConsumer;
1114

@@ -60,12 +63,15 @@
6063
import org.hibernate.persister.collection.CollectionPersister;
6164
import org.hibernate.persister.entity.EntityPersister;
6265
import org.hibernate.proxy.LazyInitializer;
66+
import org.hibernate.query.criteria.JpaCriteriaQuery;
67+
import org.hibernate.query.criteria.JpaRoot;
6368
import org.hibernate.stat.spi.StatisticsImplementor;
6469
import org.hibernate.tuple.entity.EntityMetamodel;
6570

6671
import jakarta.persistence.EntityGraph;
6772
import jakarta.transaction.SystemException;
6873

74+
import static java.util.Arrays.asList;
6975
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
7076
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
7177
import static org.hibernate.engine.internal.Versioning.incrementVersion;
@@ -510,6 +516,30 @@ public <T> T get(
510516
}
511517
}
512518

519+
@Override
520+
public <T> List<T> getAll(Class<T> entityClass, Object... ids) {
521+
for (Object id : ids) {
522+
if ( id == null ) {
523+
throw new IllegalArgumentException("Null id");
524+
}
525+
}
526+
final EntityPersister persister = getEntityPersister( entityClass.getName() );
527+
final JpaCriteriaQuery<T> query = getCriteriaBuilder().createQuery(entityClass);
528+
final JpaRoot<T> from = query.from(entityClass);
529+
query.where( from.get(persister.getIdentifierPropertyName()).in(ids) );
530+
final List<T> resultList = createSelectionQuery(query).getResultList();
531+
final List<Object> idList = new ArrayList<>(resultList.size());
532+
for (T entity : resultList) {
533+
idList.add( persister.getIdentifier(entity, this) );
534+
}
535+
final List<T> list = new ArrayList<>(ids.length);
536+
for (Object id : ids) {
537+
final int pos = idList.indexOf(id);
538+
list.add( pos < 0 ? null : resultList.get(pos) );
539+
}
540+
return list;
541+
}
542+
513543
private EntityPersister getEntityPersister(String entityName) {
514544
return getFactory().getMappingMetamodel().getEntityDescriptor( entityName );
515545
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.hibernate.orm.test.loading.multiLoad;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.Id;
5+
import org.hibernate.testing.orm.junit.DomainModel;
6+
import org.hibernate.testing.orm.junit.SessionFactory;
7+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.List;
11+
12+
import static org.junit.Assert.assertEquals;
13+
import static org.junit.Assert.assertNull;
14+
15+
@SessionFactory
16+
@DomainModel(annotatedClasses = FindAllTest.Record.class)
17+
public class FindAllTest {
18+
@Test void test(SessionFactoryScope scope) {
19+
scope.inTransaction(s-> {
20+
s.persist(new Record(123L,"hello earth"));
21+
s.persist(new Record(456L,"hello mars"));
22+
});
23+
scope.inTransaction(s-> {
24+
List<Record> all = s.findAll(Record.class, 456L, 123L, 2L);
25+
assertEquals("hello mars",all.get(0).message);
26+
assertEquals("hello earth",all.get(1).message);
27+
assertNull(all.get(2));
28+
});
29+
}
30+
@Entity
31+
static class Record {
32+
@Id Long id;
33+
String message;
34+
35+
Record(Long id, String message) {
36+
this.id = id;
37+
this.message = message;
38+
}
39+
40+
Record() {
41+
}
42+
}
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.hibernate.orm.test.stateless;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.Id;
5+
import org.hibernate.testing.orm.junit.DomainModel;
6+
import org.hibernate.testing.orm.junit.SessionFactory;
7+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.List;
11+
12+
import static org.junit.Assert.assertEquals;
13+
import static org.junit.Assert.assertNull;
14+
15+
@SessionFactory
16+
@DomainModel(annotatedClasses = GetAllTest.Record.class)
17+
public class GetAllTest {
18+
@Test void test(SessionFactoryScope scope) {
19+
scope.inStatelessTransaction(s-> {
20+
s.insert(new Record(123L,"hello earth"));
21+
s.insert(new Record(456L,"hello mars"));
22+
});
23+
scope.inStatelessTransaction(s-> {
24+
List<Record> all = s.getAll(Record.class, 456L, 123L, 2L);
25+
assertEquals("hello mars",all.get(0).message);
26+
assertEquals("hello earth",all.get(1).message);
27+
assertNull(all.get(2));
28+
});
29+
}
30+
@Entity
31+
static class Record {
32+
@Id Long id;
33+
String message;
34+
35+
Record(Long id, String message) {
36+
this.id = id;
37+
this.message = message;
38+
}
39+
40+
Record() {
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)