/* Hibernate, Relational Persistence for Idiomatic Java * * SPDX-License-Identifier: LGPL-2.1-or-later * Copyright: Red Hat Inc. and Hibernate Authors */ package org.hibernate.reactive; import io.vertx.ext.unit.TestContext; import org.hibernate.Hibernate; import org.hibernate.LockMode; import org.hibernate.annotations.BatchSize; import org.hibernate.cfg.Configuration; import org.junit.Test; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.Version; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class BatchFetchTest extends BaseReactiveTest { @Override protected Configuration constructConfiguration() { Configuration configuration = super.constructConfiguration(); configuration.addAnnotatedClass( Node.class ); configuration.addAnnotatedClass( Element.class ); return configuration; } @Test public void testQuery(TestContext context) { Node basik = new Node("Child"); basik.parent = new Node("Parent"); basik.elements.add(new Element(basik)); basik.elements.add(new Element(basik)); basik.elements.add(new Element(basik)); basik.parent.elements.add(new Element(basik.parent)); basik.parent.elements.add(new Element(basik.parent)); test( context, openSession() .thenCompose(s -> s.persist(basik)) .thenCompose(s -> s.flush()) .thenCompose(v -> openSession()) .thenCompose(s -> s.createQuery("from Node n order by id", Node.class) .getResultList() .thenCompose( list -> { context.assertEquals(list.size(), 2); Node n1 = list.get(0); Node n2 = list.get(1); context.assertFalse( Hibernate.isInitialized(n1.elements) ); context.assertFalse( Hibernate.isInitialized(n2.elements) ); return s.fetch( n1.elements ).thenAccept( elements -> { context.assertTrue( Hibernate.isInitialized(elements) ); context.assertTrue( Hibernate.isInitialized(n1.elements) ); context.assertTrue( Hibernate.isInitialized(n2.elements) ); } ); }) ) .thenCompose(v -> openSession()) .thenCompose(s -> s.createQuery("from Element e order by id", Element.class) .getResultList() .thenCompose( list -> { context.assertEquals( list.size(), 5 ); list.forEach( element -> context.assertFalse( Hibernate.isInitialized(element.node) ) ); list.forEach( element -> context.assertEquals(s.getLockMode(element.node), LockMode.NONE) ); return s.fetch( list.get(0).node ) .thenAccept( node -> { context.assertTrue( Hibernate.isInitialized(node) ); //TODO: I would like to assert that they're all initialized // but apparently it doesn't set the proxies to init'd // so check the LockMode as a workaround list.forEach( element -> context.assertEquals(s.getLockMode(element.node), LockMode.READ) ); }); }) ) ); } @Entity(name = "Element") @Table(name="Element") public static class Element { @Id @GeneratedValue Integer id; @ManyToOne(fetch = FetchType.LAZY) Node node; public Element(Node node) { this.node = node; } Element() {} } @Entity(name = "Node") @Table(name="Node") @BatchSize(size=5) public static class Node { @Id @GeneratedValue Integer id; @Version Integer version; String string; @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE}) Node parent; @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, mappedBy = "node") @BatchSize(size=5) List<Element> elements = new ArrayList<>(); @Transient boolean prePersisted; @Transient boolean postPersisted; @Transient boolean preUpdated; @Transient boolean postUpdated; @Transient boolean postRemoved; @Transient boolean preRemoved; @Transient boolean loaded; public Node(String string) { this.string = string; } Node() {} @PrePersist void prePersist() { prePersisted = true; } @PostPersist void postPersist() { postPersisted = true; } @PreUpdate void preUpdate() { preUpdated = true; } @PostUpdate void postUpdate() { postUpdated = true; } @PreRemove void preRemove() { preRemoved = true; } @PostRemove void postRemove() { postRemoved = true; } @PostLoad void postLoad() { loaded = true; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getString() { return string; } public void setString(String string) { this.string = string; } @Override public String toString() { return id + ": " + string; } @Override public boolean equals(Object o) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } Node node = (Node) o; return Objects.equals(string, node.string); } @Override public int hashCode() { return Objects.hash(string); } } }