From 2aab966e3227798ebfdc9f88d837beb393ad0502 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 24 Jun 2024 09:25:21 +0200 Subject: [PATCH] fix --- ...ReactiveAbstractCollectionInitializer.java | 9 + .../ReactiveCollectionDomainResult.java | 88 ++++++++- .../internal/ReactiveListInitializer.java | 157 +++++++++++++++ .../ReactiveEntityInitializerImpl.java | 32 ++-- .../reactive/ORMReactivePersistenceTest.java | 107 ++++------- .../reactive/OrderedOneToManyTest.java | 180 ++++++++---------- 6 files changed, 393 insertions(+), 180 deletions(-) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveAbstractCollectionInitializer.java create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveListInitializer.java diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveAbstractCollectionInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveAbstractCollectionInitializer.java new file mode 100644 index 0000000000..c49c452a1a --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveAbstractCollectionInitializer.java @@ -0,0 +1,9 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.sql.results.graph.collection.internal; + +public class ReactiveAbstractCollectionInitializer { +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveCollectionDomainResult.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveCollectionDomainResult.java index 6a60e89dba..e55d0a34a2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveCollectionDomainResult.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveCollectionDomainResult.java @@ -5,19 +5,32 @@ */ package org.hibernate.reactive.sql.results.graph.collection.internal; + +import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityFetchJoinedImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.InitializerData; +import org.hibernate.sql.results.graph.InitializerParent; +import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult; import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl; +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; + +import static java.lang.invoke.MethodHandles.lookup; +import static org.hibernate.reactive.logging.impl.LoggerFactory.make; public class ReactiveCollectionDomainResult extends CollectionDomainResult { + private static final Log LOG = make( Log.class, lookup() ); + public ReactiveCollectionDomainResult( NavigablePath loadingPath, PluralAttributeMapping loadingAttribute, @@ -48,4 +61,77 @@ public Fetch generateFetchableFetch( } return fetch; } -} + + @Override + public CollectionInitializer createInitializer( + InitializerParent parent, + AssemblerCreationState creationState) { + CollectionInitializer initializer = super.createInitializer( parent, creationState ); + return new ReactiveCollectionInitializerAdapter<>( initializer ); + } + + public static class ReactiveCollectionInitializerAdapter + implements CollectionInitializer { + + private final CollectionInitializer delegate; + + public ReactiveCollectionInitializerAdapter(CollectionInitializer initializer) { + this.delegate = initializer; + } + + @Override + public NavigablePath getNavigablePath() { + return delegate.getNavigablePath(); + } + + @Override + public PluralAttributeMapping getInitializedPart() { + return delegate.getInitializedPart(); + } + + @Override + public T getData(RowProcessingState rowProcessingState) { + return delegate.getData( rowProcessingState ); + } + + @Override + public void startLoading(RowProcessingState rowProcessingState) { + delegate.startLoading( rowProcessingState ); + } + + @Override + public void resolveKey(T data) { + throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); + } + + @Override + public void resolveInstance(T data) { + throw LOG.nonReactiveMethodCall( "reactiveResolveInstance" ); + } + + @Override + public void initializeInstance(T data) { + delegate.initializeInstance( data ); + } + + @Override + public void finishUpRow(T data) { + delegate.finishUpRow( data ); + } + + @Override + public boolean isPartOfKey() { + return delegate.isPartOfKey(); + } + + @Override + public boolean isResultInitializer() { + return delegate.isResultInitializer(); + } + + @Override + public PersistentCollection getCollectionInstance(T data) { + return delegate.getCollectionInstance( data ); + } + } + } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveListInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveListInitializer.java new file mode 100644 index 0000000000..53a1494830 --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/collection/internal/ReactiveListInitializer.java @@ -0,0 +1,157 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.sql.results.graph.collection.internal; + +import java.util.List; +import java.util.function.BiConsumer; + +import org.hibernate.HibernateException; +import org.hibernate.LockMode; +import org.hibernate.collection.spi.PersistentList; +import org.hibernate.engine.spi.CollectionKey; +import org.hibernate.internal.log.LoggingHelper; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.InitializerData; +import org.hibernate.sql.results.graph.InitializerParent; +import org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer; +import org.hibernate.sql.results.graph.collection.internal.ListInitializer; +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; + +public class ReactiveListInitializer + extends AbstractImmediateCollectionInitializer { + private static final String CONCRETE_NAME = ListInitializer.class.getSimpleName(); + + private final DomainResultAssembler listIndexAssembler; + private final DomainResultAssembler elementAssembler; + + private final int listIndexBase; + + public ReactiveListInitializer( + NavigablePath navigablePath, + PluralAttributeMapping attributeMapping, + InitializerParent parent, + LockMode lockMode, + DomainResult collectionKeyResult, + DomainResult collectionValueKeyResult, + boolean isResultInitializer, + AssemblerCreationState creationState, + Fetch listIndexFetch, + Fetch elementFetch) { + super( + navigablePath, + attributeMapping, + parent, + lockMode, + collectionKeyResult, + collectionValueKeyResult, + isResultInitializer, + creationState + ); + //noinspection unchecked + this.listIndexAssembler = (DomainResultAssembler) listIndexFetch.createAssembler( + this, + creationState + ); + this.elementAssembler = elementFetch.createAssembler( this, creationState ); + this.listIndexBase = attributeMapping.getIndexMetadata().getListIndexBase(); + } + + @Override + protected String getSimpleConcreteImplName() { + return CONCRETE_NAME; + } + + @Override + protected void forEachSubInitializer( + BiConsumer, RowProcessingState> consumer, + InitializerData data) { + super.forEachSubInitializer( consumer, data ); + final Initializer initializer = elementAssembler.getInitializer(); + if ( initializer != null ) { + consumer.accept( initializer, data.getRowProcessingState() ); + } + } + + @Override + public PersistentList getCollectionInstance(ImmediateCollectionInitializerData data) { + return (PersistentList) super.getCollectionInstance( data ); + } + + @Override + protected void readCollectionRow( + CollectionKey collectionKey, + List loadingState, + RowProcessingState rowProcessingState) { + final Integer indexValue = listIndexAssembler.assemble( rowProcessingState ); + if ( indexValue == null ) { + throw new HibernateException( "Illegal null value for list index encountered while reading: " + + getCollectionAttributeMapping().getNavigableRole() ); + } + final Object element = elementAssembler.assemble( rowProcessingState ); + if ( element == null ) { + // If element is null, then NotFoundAction must be IGNORE + return; + } + int index = indexValue; + + if ( listIndexBase != 0 ) { + index -= listIndexBase; + } + + for ( int i = loadingState.size(); i <= index; ++i ) { + loadingState.add( i, null ); + } + + loadingState.set( index, element ); + } + + @Override + protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerData data) { + final Initializer initializer = elementAssembler.getInitializer(); + if ( initializer != null ) { + final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final PersistentList list = getCollectionInstance( data ); + assert list != null; + for ( Object element : list ) { + initializer.initializeInstanceFromParent( element, rowProcessingState ); + } + } + } + + @Override + protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { + final Initializer initializer = elementAssembler.getInitializer(); + if ( initializer != null ) { + final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final PersistentList list = getCollectionInstance( data ); + assert list != null; + for ( Object element : list ) { + initializer.resolveInstance( element, rowProcessingState ); + } + } + } + + @Override + public DomainResultAssembler getIndexAssembler() { + return listIndexAssembler; + } + + @Override + public DomainResultAssembler getElementAssembler() { + return elementAssembler; + } + + @Override + public String toString() { + return "ReactiveListInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + } +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java index 8fb9abcfdf..94f78dbea6 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java @@ -808,22 +808,22 @@ public void resolveInstance(Object instance, EntityInitializerData data) { public void resolveInstance(EntityInitializerData data) { throw LOG.nonReactiveMethodCall( "reactiveResolveInstance" ); } -// -// @Override -// protected void resolveKey(EntityInitializerData data, boolean entityKeyOnly) { -// throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); -// } -// -// @Override -// public void resolveKey(EntityInitializerData data) { -// throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); -// } -// -// @Override -// public void resolveKey(RowProcessingState rowProcessingState) { -// throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); -// } -// + + @Override + protected void resolveKey(EntityInitializerData data, boolean entityKeyOnly) { + throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); + } + + @Override + public void resolveKey(EntityInitializerData data) { + throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); + } + + @Override + public void resolveKey(RowProcessingState rowProcessingState) { + throw LOG.nonReactiveMethodCall( "reactiveResolveKey" ); + } + @Override protected void resolveInstanceSubInitializers(EntityInitializerData data) { diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ORMReactivePersistenceTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ORMReactivePersistenceTest.java index 8d478d26a6..97afab30ec 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ORMReactivePersistenceTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ORMReactivePersistenceTest.java @@ -5,9 +5,9 @@ */ package org.hibernate.reactive; +import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletionStage; import org.hibernate.Session; @@ -23,8 +23,12 @@ import org.junit.jupiter.api.Test; import io.vertx.junit5.Timeout; +import jakarta.persistence.Basic; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; import jakarta.persistence.Table; import static java.util.concurrent.TimeUnit.MINUTES; @@ -48,7 +52,7 @@ public class ORMReactivePersistenceTest extends BaseReactiveTest { @Override protected Collection> annotatedEntities() { - return List.of( Flour.class ); + return List.of( Book.class, Author.class ); } @BeforeEach @@ -71,17 +75,24 @@ public void closeOrmFactory() { @Test public void testORMWitMutinySession() { - final Flour rose = new Flour( 2, "Rose", "made from ground rose pedals.", "Full fragrance" ); + Book endjinn = new Book( "Feersum Endjinn" ); + Book useOfWeapons = new Book( "Use of Weapons" ); + Author ian = new Author( "Iain M Banks" ); + ian.books.add( endjinn ); + ian.books.add( useOfWeapons ); try (Session ormSession = ormFactory.openSession()) { ormSession.beginTransaction(); - ormSession.persist( rose ); + ormSession.persist( endjinn ); + ormSession.persist( useOfWeapons ); + ormSession.persist( ian ); ormSession.getTransaction().commit(); } try (Session ormSession = ormFactory.openSession()) { ormSession.beginTransaction(); - Flour flour = ormSession.find( Flour.class, rose.id ); + Author author = ormSession.find( Author.class, ian.id ); + List books = author.books; ormSession.getTransaction().commit(); } } @@ -91,79 +102,43 @@ protected CompletionStage cleanDb() { return CompletionStages.voidFuture(); } - @Entity(name = "Flour") - @Table(name = "Flour") - public static class Flour { - @Id - private Integer id; - private String name; - private String description; - private String type; - - public Flour() { - } - - public Flour(Integer id, String name, String description, String type) { - this.id = id; - this.name = name; - this.description = description; - this.type = type; + @Entity(name = "Book") + @Table(name = "OTMBook") + static class Book { + Book(String title) { + this.title = title; } - public Integer getId() { - return id; + Book() { } - public void setId(Integer id) { - this.id = id; - } + @GeneratedValue + @Id + long id; - public String getName() { - return name; - } + @Basic(optional = false) + String title; + } - public void setName(String name) { + @Entity(name = "Author") + @Table(name = "OTMAuthor") + static class Author { + Author(String name) { this.name = name; } - public String getDescription() { - return description; + public Author() { } - public void setDescription(String description) { - this.description = description; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @Override - public String toString() { - return id + ":" + name; - } + @GeneratedValue + @Id + long id; - @Override - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - if ( o == null || getClass() != o.getClass() ) { - return false; - } - Flour flour = (Flour) o; - return Objects.equals( name, flour.name ) && - Objects.equals( description, flour.description ) && - Objects.equals( type, flour.type ); - } + @Basic(optional = false) + String name; - @Override - public int hashCode() { - return Objects.hash( name, description, type ); - } + @OneToMany + @OrderColumn(name = "list_index") + List books = new ArrayList<>(); } } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderedOneToManyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderedOneToManyTest.java index 7edfa6e746..8955e94d04 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderedOneToManyTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OrderedOneToManyTest.java @@ -48,105 +48,91 @@ public void test(VertxTestContext context) { test( context, getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.persistAll( book1, book2, author ) ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> assertEquals( 2, books.size() ) ) + .withTransaction( session -> session.persistAll( book1, book2, author ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> assertEquals( 2, books.size() ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .createSelectionQuery( + "select distinct a from Author a left join fetch a.books", + Author.class ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.createSelectionQuery( - "select distinct a from Author a left join fetch a.books", - Author.class - ) - .getSingleResult() - .invoke( a -> assertTrue( Hibernate.isInitialized( a.books ) ) ) - .invoke( a -> assertEquals( 2, a.books.size() ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> books.remove( 0 ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> { - assertEquals( 1, books.size() ); - assertEquals( book2.title, books.get( 0 ).title ); - } ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .chain( books -> session.find( Book.class, book1.id ).invoke( books::add ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> assertEquals( 2, books.size() ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> books.remove( 1 ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> { - assertEquals( 1, books.size() ); - assertEquals( book2.title, books.get( 0 ).title ); - } ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .chain( books -> session.find( Book.class, book1.id ).invoke( books::add ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> assertEquals( 2, books.size() ) ) - ) - ) + .getSingleResult() + .invoke( a -> assertTrue( Hibernate.isInitialized( a.books ) ) ) + .invoke( a -> assertEquals( 2, a.books.size() ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> books.remove( 0 ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> { + assertEquals( 1, books.size() ); + assertEquals( book2.title, books.get( 0 ).title ); + } ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .chain( books -> session.find( Book.class, book1.id ).invoke( books::add ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> assertEquals( 2, books.size() ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> books.remove( 1 ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> { + assertEquals( 1, books.size() ); + assertEquals( book2.title, books.get( 0 ).title ); + } ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .chain( books -> session.find( Book.class, book1.id ).invoke( books::add ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> assertEquals( 2, books.size() ) ) + ) ) //TODO: this is broken, but I suspect it is broken in core also! -// .chain( () -> getMutinySessionFactory() -// .withTransaction( (session, transaction) -> session.find(Author.class, author.id) -// .chain( a -> session.fetch(a.books) ) -// .invoke( books -> books.add( books.remove(0) ) ) -// ) -// ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> assertEquals( 2, books.size() ) ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .invoke( a -> a.books = null ) - ) - ) - .chain( () -> getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.find( Author.class, author.id ) - .chain( a -> session.fetch( a.books ) ) - .invoke( books -> assertTrue( books.isEmpty() ) ) - ) - ) +// .chain( () -> getMutinySessionFactory().withTransaction( (session, transaction) -> session +// .find( Author.class, author.id ) +// .chain( a -> session.fetch( a.books ) ) +// .invoke( books -> books.add( books.remove( 0 ) ) ) +// ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .invoke( a -> assertFalse( Hibernate.isInitialized( a.books ) ) ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> assertEquals( 2, books.size() ) ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .invoke( a -> a.books = null ) + ) ) + .chain( () -> getMutinySessionFactory().withTransaction( session -> session + .find( Author.class, author.id ) + .chain( a -> session.fetch( a.books ) ) + .invoke( books -> assertTrue( books.isEmpty() ) ) + ) ) ); }