@@ -19,10 +19,22 @@ What we're doing in Panache is to allow you to write your Hibernate ORM entities
1919
2020[source,java]
2121----
22+ package org.acme;
23+
2224public enum Status {
2325 Alive,
2426 Deceased
2527}
28+ ----
29+
30+ [source,java]
31+ ----
32+ package org.acme;
33+
34+ import java.time.LocalDate;
35+ import java.util.List;
36+ import jakarta.persistence.Entity;
37+ import io.quarkus.hibernate.orm.panache.PanacheEntity;
2638
2739@Entity
2840public class Person extends PanacheEntity {
@@ -156,6 +168,13 @@ columns as public fields:
156168
157169[source,java]
158170----
171+ package org.acme;
172+
173+ import java.time.LocalDate;
174+ import java.util.List;
175+ import jakarta.persistence.Entity;
176+ import io.quarkus.hibernate.orm.panache.PanacheEntity;
177+
159178@Entity
160179public class Person extends PanacheEntity {
161180 public String name;
@@ -169,6 +188,13 @@ You can put all your JPA column annotations on the public fields. If you need a
169188
170189[source,java]
171190----
191+ package org.acme;
192+
193+ import java.time.LocalDate;
194+ import java.util.List;
195+ import jakarta.persistence.Entity;
196+ import io.quarkus.hibernate.orm.panache.PanacheEntity;
197+
172198@Entity
173199public class Person extends PanacheEntity {
174200 public String name;
@@ -197,6 +223,11 @@ Once you have written your entity, here are the most common operations you will
197223
198224[source,java]
199225----
226+ import java.time.LocalDate;
227+ import java.time.Month;
228+ import java.util.List;
229+ import java.util.Optional;
230+
200231// creating a person
201232Person person = new Person();
202233person.name = "Stef";
@@ -252,6 +283,10 @@ All `list` methods have equivalent `stream` versions.
252283
253284[source,java]
254285----
286+ import java.util.List;
287+ import java.util.stream.Collectors;
288+ import java.util.stream.Stream;
289+
255290try (Stream<Person> persons = Person.streamAll()) {
256291 List<String> namesButEmmanuels = persons
257292 .map(p -> p.name.toLowerCase() )
@@ -272,6 +307,13 @@ Adding them as static methods in your entity class is the Panache Active Record
272307
273308[source,java]
274309----
310+ package org.acme;
311+
312+ import java.time.LocalDate;
313+ import java.util.List;
314+ import jakarta.persistence.Entity;
315+ import io.quarkus.hibernate.orm.panache.PanacheEntity;
316+
275317@Entity
276318public class Person extends PanacheEntity {
277319 public String name;
@@ -301,6 +343,12 @@ When using the repository pattern, you can define your entities as regular JPA e
301343
302344[source,java]
303345----
346+ package org.acme;
347+
348+ import jakarta.persistence.GeneratedValue;
349+ import jakarta.persistence.Id;
350+ import java.time.LocalDate;
351+
304352@Entity
305353public class Person {
306354 @Id @GeneratedValue private Long id;
@@ -345,6 +393,13 @@ by making them implements `PanacheRepository`:
345393
346394[source,java]
347395----
396+ package org.acme;
397+
398+ import io.quarkus.hibernate.orm.panache.PanacheRepository;
399+
400+ import jakarta.enterprise.context.ApplicationScoped;
401+ import java.util.List;
402+
348403@ApplicationScoped
349404public class PersonRepository implements PanacheRepository<Person> {
350405
@@ -369,6 +424,8 @@ is exactly the same as using the active record pattern, except you need to injec
369424
370425[source,java]
371426----
427+ import jakarta.inject.Inject;
428+
372429@Inject
373430PersonRepository personRepository;
374431
@@ -384,6 +441,11 @@ Once you have written your repository, here are the most common operations you w
384441
385442[source,java]
386443----
444+ import java.time.LocalDate;
445+ import java.time.Month;
446+ import java.util.List;
447+ import java.util.Optional;
448+
387449// creating a person
388450Person person = new Person();
389451person.setName("Stef");
@@ -439,6 +501,10 @@ All `list` methods have equivalent `stream` versions.
439501
440502[source,java]
441503----
504+ import java.util.List;
505+ import java.util.stream.Collectors;
506+ import java.util.stream.Stream;
507+
442508Stream<Person> persons = personRepository.streamAll();
443509List<String> namesButEmmanuels = persons
444510 .map(p -> p.name.toLowerCase() )
@@ -460,6 +526,22 @@ Then, you can create the following resource to create/read/update/delete your Pe
460526
461527[source,java]
462528----
529+ package org.acme;
530+
531+ import java.net.URI;
532+ import java.util.List;
533+ import jakarta.transaction.Transactional;
534+ import jakarta.ws.rs.Consumes;
535+ import jakarta.ws.rs.DELETE;
536+ import jakarta.ws.rs.GET;
537+ import jakarta.ws.rs.NotFoundException;
538+ import jakarta.ws.rs.POST;
539+ import jakarta.ws.rs.PUT;
540+ import jakarta.ws.rs.Path;
541+ import jakarta.ws.rs.Produces;
542+ import jakarta.ws.rs.core.MediaType;
543+ import jakarta.ws.rs.core.Response;
544+
463545@Path("/persons")
464546@Produces(MediaType.APPLICATION_JSON)
465547@Consumes(MediaType.APPLICATION_JSON)
@@ -526,6 +608,39 @@ public class PersonResource {
526608NOTE: Be careful to use the `@Transactional` annotation on the operations that modify the database,
527609you can add the annotation at the class level for simplicity purpose.
528610
611+ To make it easier to showcase some capabilities of Hibernate ORM with Panache on Quarkus with Dev mode, some test data should be inserted into the database by adding the following content to a new file named src/main/resources/import.sql:
612+
613+ [source,sql]
614+ ----
615+ INSERT INTO person (id, birth, name, status) VALUES (nextval('hibernate_sequence'), '1995-09-12', 'Emily Brown', 0);
616+ ----
617+
618+ NOTE: If you would like to initialize the DB when you start the Quarkus app in your production environment, add `quarkus.hibernate-orm.database.generation=drop-and-create` to the Quarkus startup options in addition to `import.sql`.
619+
620+ After that, you can see the people list and add new person as followings:
621+
622+ [source,shell]
623+ ----
624+ $ curl -w "\n" http://localhost:8080/persons
625+ [{"id":1,"name":"Emily Brown","birth":"1995-09-12","status":"Alive"}]
626+
627+ $ curl -X POST -H "Content-Type: application/json" -d '{"name" : "William Davis" , "birth" : "1988-07-04", "status" : "Alive"}' http://localhost:8080/persons
628+
629+ $ curl -w "\n" http://localhost:8080/persons
630+ [{"id":1,"name":"Emily Brown","birth":"1995-09-12","status":"Alive"}, {"id":2,"name":"William Davis","birth":"1988-07-04","status":"Alive"}]
631+ ----
632+
633+ NOTE: If you see the Person object as Person<1>, then the object has not been converted. In this case, add the dependency `quarkus-resteasy-reactive-jackson` in `pom.xml`.
634+
635+ [source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
636+ .pom.xml
637+ ----
638+ <dependency>
639+ <groupId>io.quarkus</groupId>
640+ <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
641+ </dependency>
642+ ----
643+
529644== Advanced Query
530645
531646=== Paging
@@ -535,6 +650,10 @@ sets you can use the `find` method equivalents, which return a `PanacheQuery` on
535650
536651[source,java]
537652----
653+ import io.quarkus.hibernate.orm.panache.PanacheQuery;
654+ import io.quarkus.panache.common.Page;
655+ import java.util.List;
656+
538657// create a query for all living persons
539658PanacheQuery<Person> livingPersons = Person.find("status", Status.Alive);
540659
@@ -571,6 +690,9 @@ The `PanacheQuery` type has many other methods to deal with paging and returning
571690
572691[source,java]
573692----
693+ import io.quarkus.hibernate.orm.panache.PanacheQuery;
694+ import java.util.List;
695+
574696// create a query for all living persons
575697PanacheQuery<Person> livingPersons = Person.find("status", Status.Alive);
576698
@@ -603,6 +725,8 @@ But these methods also accept an optional `Sort` parameter, which allows you to
603725
604726[source,java]
605727----
728+ import io.quarkus.panache.common.Sort;
729+
606730List<Person> persons = Person.list(Sort.by("name").and("birth"));
607731
608732// and with more restrictions
@@ -652,6 +776,16 @@ You can reference a named query instead of a (simplified) HQL query by prefixing
652776
653777[source,java]
654778----
779+ package org.acme;
780+
781+ import java.time.LocalDate;
782+ import jakarta.persistence.Entity;
783+ import jakarta.persistence.NamedQueries;
784+ import jakarta.persistence.NamedQuery;
785+
786+ import io.quarkus.hibernate.orm.panache.PanacheEntity;
787+ import io.quarkus.panache.common.Parameters;
788+
655789@Entity
656790@NamedQueries({
657791 @NamedQuery(name = "Person.getByName", query = "from Person where name = ?1"),
@@ -702,6 +836,9 @@ Or by name using a `Map`:
702836
703837[source,java]
704838----
839+ import java.util.HashMap;
840+ import java.util.Map;
841+
705842Map<String, Object> params = new HashMap<>();
706843params.put("name", "stef");
707844params.put("status", Status.Alive);
@@ -740,6 +877,7 @@ instantiate the projection DTO instead of using the entity class. This class mus
740877[source,java]
741878----
742879import io.quarkus.runtime.annotations.RegisterForReflection;
880+ import io.quarkus.hibernate.orm.panache.PanacheQuery;
743881
744882@RegisterForReflection // <1>
745883public class PersonName {
@@ -771,6 +909,9 @@ If in the DTO projection object you have a field from a referenced entity, you c
771909
772910[source,java]
773911----
912+ import jakarta.persistence.ManyToOne;
913+ import io.quarkus.hibernate.orm.panache.common.ProjectedFieldName;
914+
774915@Entity
775916public class Dog extends PanacheEntity {
776917 public String name;
@@ -858,6 +999,8 @@ And your transaction still has to be committed.
858999Here is an example of the usage of the flush method to allow making a specific action in case of `PersistenceException`:
8591000[source,java]
8601001----
1002+ import jakarta.persistence.PersistenceException;
1003+
8611004@Transactional
8621005public void create(Parameter parameter){
8631006 try {
@@ -882,6 +1025,10 @@ The following examples are for the active record pattern, but the same can be us
8821025
8831026[source,java]
8841027----
1028+ import jakarta.persistence.LockModeType;
1029+ import jakarta.transaction.Transactional;
1030+ import jakarta.ws.rs.GET;
1031+
8851032public class PersonEndpoint {
8861033
8871034 @GET
@@ -899,6 +1046,10 @@ public class PersonEndpoint {
8991046
9001047[source,java]
9011048----
1049+ import jakarta.persistence.LockModeType;
1050+ import jakarta.transaction.Transactional;
1051+ import jakarta.ws.rs.GET;
1052+
9021053public class PersonEndpoint {
9031054
9041055 @GET
@@ -924,6 +1075,13 @@ you just declare whatever ID you want as a public field:
9241075
9251076[source,java]
9261077----
1078+ import jakarta.persistence.Entity;
1079+ import jakarta.persistence.GeneratedValue;
1080+ import jakarta.persistence.GenerationType;
1081+ import jakarta.persistence.Id;
1082+ import jakarta.persistence.SequenceGenerator;
1083+ import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
1084+
9271085@Entity
9281086public class Person extends PanacheEntityBase {
9291087
@@ -945,6 +1103,9 @@ and specify your ID type as an extra type parameter:
9451103
9461104[source,java]
9471105----
1106+ import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
1107+ import jakarta.enterprise.context.ApplicationScoped;
1108+
9481109@ApplicationScoped
9491110public class PersonRepository implements PanacheRepositoryBase<Person,Integer> {
9501111 //...
@@ -990,6 +1151,14 @@ You can write your mocking test like this:
9901151
9911152[source,java]
9921153----
1154+ import io.quarkus.panache.mock.PanacheMock;
1155+ import io.quarkus.test.junit.QuarkusTest;
1156+ import org.junit.jupiter.api.Assertions;
1157+ import org.junit.jupiter.api.Test;
1158+ import org.mockito.Mockito;
1159+ import jakarta.ws.rs.WebApplicationException;
1160+ import java.util.Collections;
1161+
9931162@QuarkusTest
9941163public class PanacheFunctionalityTest {
9951164
@@ -1070,6 +1239,15 @@ If you need to mock entity instance methods, such as `persist()` you can do it b
10701239
10711240[source,java]
10721241----
1242+ import io.quarkus.test.junit.QuarkusTest;
1243+ import io.quarkus.test.junit.mockito.InjectMock;
1244+ import org.hibernate.Session;
1245+ import org.hibernate.query.Query;
1246+ import org.junit.jupiter.api.Assertions;
1247+ import org.junit.jupiter.api.BeforeEach;
1248+ import org.junit.jupiter.api.Test;
1249+ import org.mockito.Mockito;
1250+
10731251@QuarkusTest
10741252public class PanacheMockingTest {
10751253
@@ -1141,6 +1319,14 @@ You can write your mocking test like this:
11411319
11421320[source,java]
11431321----
1322+ import io.quarkus.test.junit.QuarkusTest;
1323+ import io.quarkus.test.junit.mockito.InjectMock;
1324+ import org.junit.jupiter.api.Assertions;
1325+ import org.junit.jupiter.api.Test;
1326+ import org.mockito.Mockito;
1327+ import jakarta.ws.rs.WebApplicationException;
1328+ import java.util.Collections;
1329+
11441330@QuarkusTest
11451331public class PanacheFunctionalityTest {
11461332 @InjectMock
0 commit comments