diff --git a/004-quarkus-HHH-and-HV/README.md b/004-quarkus-HHH-and-HV/README.md
index 844bdb77..b1c6047d 100644
--- a/004-quarkus-HHH-and-HV/README.md
+++ b/004-quarkus-HHH-and-HV/README.md
@@ -1,3 +1,7 @@
# Quarkus - Hibernate and Hibernate Validator (lazy fetch strategy)
This scenario uses in-memory Java database H2.
-Test class annotated with `@QuarkusTestResource(H2DatabaseTestResource.class)` starts an in-memory H2 database
\ No newline at end of file
+Test class annotated with `@QuarkusTestResource(H2DatabaseTestResource.class)` starts an in-memory H2 database
+
+Module that covers intergation with some Hibernate features like:
+- Usage of Code Generator: `hibernate-jpamodelgen` dependency
+- Reproducer for [14201](https://github.com/quarkusio/quarkus/issues/14201) and [14881](https://github.com/quarkusio/quarkus/issues/14881): possible data loss bug in hibernate
\ No newline at end of file
diff --git a/004-quarkus-HHH-and-HV/pom.xml b/004-quarkus-HHH-and-HV/pom.xml
index d1804e35..6cdc5462 100644
--- a/004-quarkus-HHH-and-HV/pom.xml
+++ b/004-quarkus-HHH-and-HV/pom.xml
@@ -38,6 +38,11 @@
io.quarkus
quarkus-hibernate-validator
+
+ org.hibernate
+ hibernate-jpamodelgen
+ provided
+
io.quarkus
quarkus-test-h2
diff --git a/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Account.java b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Account.java
new file mode 100644
index 00000000..17d4c5c1
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Account.java
@@ -0,0 +1,37 @@
+package io.quarkus.qe.hibernate.items;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Entity
+public class Account {
+
+ @Id
+ public Long id;
+
+ @Column(length = 255, unique = true, nullable = false)
+ @NotNull
+ @Size(max = 255)
+ public String email;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date createdOn;
+
+ @ManyToMany(fetch = FetchType.LAZY)
+ @JoinTable(name = "account_in_role", joinColumns = @JoinColumn(name = "accountid"), inverseJoinColumns = @JoinColumn(name = "roleid"))
+ public Set roles = new HashSet<>();
+
+}
diff --git a/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Customer.java b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Customer.java
new file mode 100644
index 00000000..795ff457
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Customer.java
@@ -0,0 +1,32 @@
+package io.quarkus.qe.hibernate.items;
+
+import java.util.Date;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Version;
+
+@Entity
+public class Customer {
+
+ @Id
+ public Long id;
+
+ @Version
+ @Column(name = "version")
+ public int version;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date createdOn;
+
+ @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
+ public Account account;
+
+
+}
\ No newline at end of file
diff --git a/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Item.java b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Item.java
new file mode 100644
index 00000000..9c0a78b3
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Item.java
@@ -0,0 +1,21 @@
+package io.quarkus.qe.hibernate.items;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class Item {
+
+ @Id
+ public Long id;
+
+ public String note;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "customerId")
+ public Customer customer;
+
+}
diff --git a/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/ItemsResource.java b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/ItemsResource.java
new file mode 100644
index 00000000..747cf057
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/ItemsResource.java
@@ -0,0 +1,33 @@
+package io.quarkus.qe.hibernate.items;
+
+import javax.inject.Inject;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Join;
+import javax.persistence.criteria.Root;
+import javax.transaction.Transactional;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+@Path("/items")
+@Transactional
+public class ItemsResource {
+
+ @Inject
+ EntityManager em;
+
+ @GET
+ @Path("/count")
+ public int countOrders() {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery- cq = cb.createQuery(Item.class);
+ Root
- root = cq.from(Item.class);
+ Join
- custJoin = (Join
- ) root.fetch(Item_.customer);
+
+ TypedQuery
- query = em.createQuery(cq);
+ return query.getResultList().size();
+ }
+
+}
diff --git a/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Role.java b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Role.java
new file mode 100644
index 00000000..a1dcff87
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/java/io/quarkus/qe/hibernate/items/Role.java
@@ -0,0 +1,16 @@
+package io.quarkus.qe.hibernate.items;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class Role {
+
+ @Id
+ public Long id;
+
+ @Column
+ public String name;
+
+}
\ No newline at end of file
diff --git a/004-quarkus-HHH-and-HV/src/main/resources/application.properties b/004-quarkus-HHH-and-HV/src/main/resources/application.properties
index 93f79a85..fd8e4138 100644
--- a/004-quarkus-HHH-and-HV/src/main/resources/application.properties
+++ b/004-quarkus-HHH-and-HV/src/main/resources/application.properties
@@ -3,4 +3,5 @@ quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test
quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
quarkus.datasource.jdbc.min-size=3
quarkus.datasource.jdbc.max-size=10
-quarkus.hibernate-orm.database.generation=drop-and-create
\ No newline at end of file
+quarkus.hibernate-orm.database.generation=drop-and-create
+quarkus.hibernate-orm.sql-load-script=import.sql
\ No newline at end of file
diff --git a/004-quarkus-HHH-and-HV/src/main/resources/import.sql b/004-quarkus-HHH-and-HV/src/main/resources/import.sql
new file mode 100644
index 00000000..84a30fc4
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/main/resources/import.sql
@@ -0,0 +1,12 @@
+truncate table item cascade ;
+truncate table customer cascade ;
+truncate table account_in_role cascade ;
+truncate table account cascade ;
+truncate table role cascade ;
+start TRANSACTION ;
+insert into account (id, email) values (1, 'foo@bar.com');
+insert into role (id, name) values (1, 'admin');
+insert into account_in_role (accountid, roleid) values (1, 1);
+insert into customer (id, version, account_id) values (1, 1, 1);
+insert into item (id, note, customerid) values (1, 'Item 1', 1);
+commit;
\ No newline at end of file
diff --git a/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/ItemsResourceTest.java b/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/ItemsResourceTest.java
new file mode 100644
index 00000000..973ef49d
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/ItemsResourceTest.java
@@ -0,0 +1,20 @@
+package io.quarkus.qe.hibernate.items;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.is;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+public class ItemsResourceTest {
+
+ /**
+ * Required data is pulled in from the `import.sql` resource.
+ */
+ @Test
+ public void shouldNotFailWithConstraints() {
+ given().when().get("/items/count").then().body(is("1"));
+ }
+}
diff --git a/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/NativeItemsResourceIT.java b/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/NativeItemsResourceIT.java
new file mode 100644
index 00000000..47ecccca
--- /dev/null
+++ b/004-quarkus-HHH-and-HV/src/test/java/io/quarkus/qe/hibernate/items/NativeItemsResourceIT.java
@@ -0,0 +1,7 @@
+package io.quarkus.qe.hibernate.items;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+public class NativeItemsResourceIT extends ItemsResourceTest {
+}