HHH-17948 add Session.findAll(), StatelessSession.getAll()
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
250a59a1c7
commit
526e282c4c
|
@ -126,8 +126,8 @@ public interface MultiIdentifierLoadAccess<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should {@link #multiLoad} return entity instances that have been
|
* Should {@link #multiLoad} return entity instances that have been
|
||||||
* {@link Session#remove(Object) marked for removal} in the current
|
* {@linkplain Session#remove(Object) marked for removal} in the
|
||||||
* session, but not yet {@code delete}d in the database?
|
* current session, but not yet {@code delete}d in the database?
|
||||||
* <p>
|
* <p>
|
||||||
* By default, instances marked for removal are replaced by null in
|
* By default, instances marked for removal are replaced by null in
|
||||||
* the returned list of entities when {@link #enableOrderedReturn}
|
* the returned list of entities when {@link #enableOrderedReturn}
|
||||||
|
|
|
@ -691,6 +691,26 @@ public interface Session extends SharedSessionContract, EntityManager {
|
||||||
*/
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the persistent instances of the given entity class with the given identifiers
|
||||||
|
* as a list. The position of an instance in the list matches the position of its identifier
|
||||||
|
* in the given array, and the list contains a null value if there is no persistent instance
|
||||||
|
* matching a given identifier. If an instance is already associated with the session, that
|
||||||
|
* instance is returned. This method never returns an uninitialized instance.
|
||||||
|
* <p>
|
||||||
|
* Every object returned by {@code findAll()} is either an unproxied instance of the given
|
||||||
|
* entity class, or a fully-fetched proxy object.
|
||||||
|
*
|
||||||
|
* @param entityType the entity type
|
||||||
|
* @param ids the identifiers
|
||||||
|
*
|
||||||
|
* @return an ordered list of persistent instances, with null elements representing missing
|
||||||
|
* entities
|
||||||
|
*
|
||||||
|
* @since 6.5
|
||||||
|
*/
|
||||||
|
<E> List<E> findAll(Class<E> entityType, Object... ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the persistent instance of the given entity class with the given identifier,
|
* Return the persistent instance of the given entity class with the given identifier,
|
||||||
* or null if there is no such persistent instance. If the instance is already associated
|
* 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 {
|
||||||
* <p>
|
* <p>
|
||||||
* This operation is very similar to {@link #find(Class, Object)}.
|
* This operation is very similar to {@link #find(Class, Object)}.
|
||||||
* <p>
|
* <p>
|
||||||
* The object returned by {@code get()} or {@code find() } is either an unproxied instance
|
* The object returned by {@code get()} or {@code find()} is either an unproxied instance
|
||||||
* of the given entity class, of a fully-fetched proxy object.
|
* of the given entity class, or a fully-fetched proxy object.
|
||||||
* <p>
|
* <p>
|
||||||
* This operation requests {@link LockMode#NONE}, that is, no lock, allowing the object
|
* This operation requests {@link LockMode#NONE}, that is, no lock, allowing the object
|
||||||
* to be retrieved from the cache without the cost of database access. However, if it is
|
* to be retrieved from the cache without the cost of database access. However, if it is
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate;
|
||||||
import jakarta.persistence.EntityGraph;
|
import jakarta.persistence.EntityGraph;
|
||||||
import org.hibernate.graph.GraphSemantic;
|
import org.hibernate.graph.GraphSemantic;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command-oriented API often used for performing bulk operations against
|
* A command-oriented API often used for performing bulk operations against
|
||||||
* the database. A stateless session has no persistence context, and always
|
* the database. A stateless session has no persistence context, and always
|
||||||
|
@ -250,6 +252,23 @@ public interface StatelessSession extends SharedSessionContract {
|
||||||
*/
|
*/
|
||||||
<T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id, LockMode lockMode);
|
<T> T get(EntityGraph<T> graph, GraphSemantic graphSemantic, Object id, LockMode lockMode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve multiple rows, returning entity instances in a
|
||||||
|
* list where the position of an instance in the list matches
|
||||||
|
* the position of its identifier in the given array, and the
|
||||||
|
* list contains a null value if there is no persistent
|
||||||
|
* instance matching a given identifier.
|
||||||
|
*
|
||||||
|
* @param entityClass The class of the entity to retrieve
|
||||||
|
* @param ids The ids of the entities to retrieve
|
||||||
|
*
|
||||||
|
* @return an ordered list of detached entity instances, with
|
||||||
|
* null elements representing missing entities
|
||||||
|
*
|
||||||
|
* @since 6.5
|
||||||
|
*/
|
||||||
|
<T> List<T> getAll(Class<T> entityClass, Object... ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the entity instance state from the database.
|
* Refresh the entity instance state from the database.
|
||||||
*
|
*
|
||||||
|
|
|
@ -953,6 +953,11 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
|
||||||
delegate.detach( entity );
|
delegate.detach( entity );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
|
||||||
|
return delegate.findAll( entityType, ids );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Class<T> theClass, Object id) {
|
public <T> T get(Class<T> theClass, Object id) {
|
||||||
return delegate.get( theClass, id );
|
return delegate.get( theClass, id );
|
||||||
|
|
|
@ -263,6 +263,11 @@ public class SessionLazyDelegator implements Session {
|
||||||
this.lazySession.get().clear();
|
this.lazySession.get().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
|
||||||
|
return this.lazySession.get().findAll( entityType, ids );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Class<T> entityType, Object id) {
|
public <T> T get(Class<T> entityType, Object id) {
|
||||||
return this.lazySession.get().get( entityType, id );
|
return this.lazySession.get().get( entityType, id );
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.sql.Connection;
|
||||||
import java.sql.NClob;
|
import java.sql.NClob;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
@ -946,6 +947,11 @@ public class SessionImpl
|
||||||
return this.byId( entityName ).getReference( id );
|
return this.byId( entityName ).getReference( id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <E> List<E> findAll(Class<E> entityType, Object... ids) {
|
||||||
|
return this.byMultipleIds( entityType ).multiLoad( ids );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
|
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
|
||||||
return this.byId( entityClass ).load( id );
|
return this.byId( entityClass ).load( id );
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.internal;
|
package org.hibernate.internal;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
@ -60,12 +63,15 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
|
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||||
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
|
|
||||||
import jakarta.persistence.EntityGraph;
|
import jakarta.persistence.EntityGraph;
|
||||||
import jakarta.transaction.SystemException;
|
import jakarta.transaction.SystemException;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
||||||
import static org.hibernate.engine.internal.Versioning.incrementVersion;
|
import static org.hibernate.engine.internal.Versioning.incrementVersion;
|
||||||
|
@ -510,6 +516,30 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> List<T> getAll(Class<T> entityClass, Object... ids) {
|
||||||
|
for (Object id : ids) {
|
||||||
|
if ( id == null ) {
|
||||||
|
throw new IllegalArgumentException("Null id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final EntityPersister persister = getEntityPersister( entityClass.getName() );
|
||||||
|
final JpaCriteriaQuery<T> query = getCriteriaBuilder().createQuery(entityClass);
|
||||||
|
final JpaRoot<T> from = query.from(entityClass);
|
||||||
|
query.where( from.get(persister.getIdentifierPropertyName()).in(ids) );
|
||||||
|
final List<T> resultList = createSelectionQuery(query).getResultList();
|
||||||
|
final List<Object> idList = new ArrayList<>(resultList.size());
|
||||||
|
for (T entity : resultList) {
|
||||||
|
idList.add( persister.getIdentifier(entity, this) );
|
||||||
|
}
|
||||||
|
final List<T> list = new ArrayList<>(ids.length);
|
||||||
|
for (Object id : ids) {
|
||||||
|
final int pos = idList.indexOf(id);
|
||||||
|
list.add( pos < 0 ? null : resultList.get(pos) );
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
private EntityPersister getEntityPersister(String entityName) {
|
private EntityPersister getEntityPersister(String entityName) {
|
||||||
return getFactory().getMappingMetamodel().getEntityDescriptor( entityName );
|
return getFactory().getMappingMetamodel().getEntityDescriptor( entityName );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.hibernate.orm.test.loading.multiLoad;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
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.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses = FindAllTest.Record.class)
|
||||||
|
public class FindAllTest {
|
||||||
|
@Test void test(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
s.persist(new Record(123L,"hello earth"));
|
||||||
|
s.persist(new Record(456L,"hello mars"));
|
||||||
|
});
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
List<Record> all = s.findAll(Record.class, 456L, 123L, 2L);
|
||||||
|
assertEquals("hello mars",all.get(0).message);
|
||||||
|
assertEquals("hello earth",all.get(1).message);
|
||||||
|
assertNull(all.get(2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
static class Record {
|
||||||
|
@Id Long id;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
Record(Long id, String message) {
|
||||||
|
this.id = id;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Record() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
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.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses = GetAllTest.Record.class)
|
||||||
|
public class GetAllTest {
|
||||||
|
@Test void test(SessionFactoryScope scope) {
|
||||||
|
scope.inStatelessTransaction(s-> {
|
||||||
|
s.insert(new Record(123L,"hello earth"));
|
||||||
|
s.insert(new Record(456L,"hello mars"));
|
||||||
|
});
|
||||||
|
scope.inStatelessTransaction(s-> {
|
||||||
|
List<Record> all = s.getAll(Record.class, 456L, 123L, 2L);
|
||||||
|
assertEquals("hello mars",all.get(0).message);
|
||||||
|
assertEquals("hello earth",all.get(1).message);
|
||||||
|
assertNull(all.get(2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
static class Record {
|
||||||
|
@Id Long id;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
Record(Long id, String message) {
|
||||||
|
this.id = id;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Record() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue