diff --git a/examples/README.md b/examples/README.md
index 77699970..9a45c9b6 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -9,4 +9,5 @@
* *docker-test-containers* - TestContainers
* *spring-cloud-demo-stvort* - Config server, Eureka, Zuul, Feign client
* *spring-mail-integration-demo* - SpringMail SpringIntegration
-* *liquibase-demo* - liquibase
\ No newline at end of file
+* *liquibase-demo* - liquibase
+* *jpql-demo* - JPQL
\ No newline at end of file
diff --git a/examples/jpql-demo/.gitignore b/examples/jpql-demo/.gitignore
new file mode 100644
index 00000000..153c9335
--- /dev/null
+++ b/examples/jpql-demo/.gitignore
@@ -0,0 +1,29 @@
+HELP.md
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
+
+### VS Code ###
+.vscode/
diff --git a/examples/jpql-demo/README.md b/examples/jpql-demo/README.md
new file mode 100644
index 00000000..67632929
--- /dev/null
+++ b/examples/jpql-demo/README.md
@@ -0,0 +1,6 @@
+## Пример работы с JPQL
+
+В примере демонстрируется:
+* *репозитории на Spring ORM с использованием JPA и JPQL*
+* *использование JPQL для написания разного рода запросов (в т.ч. для выборки, агрегации, изменения и удаления данных)*
+* *тестирование репозиториев на Spring ORM с использованием @DataJpaTest*
diff --git a/examples/jpql-demo/pom.xml b/examples/jpql-demo/pom.xml
new file mode 100644
index 00000000..c4b184f3
--- /dev/null
+++ b/examples/jpql-demo/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.1.RELEASE
+
+
+
+ ru.otus.example
+ jpql-demo
+ 0.0.1-SNAPSHOT
+ jpql-demo
+ Demo project for Spring Boot
+
+
+ 11
+ 11
+ 11
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ org.springframework.shell
+ spring-shell-starter
+ 2.0.1.RELEASE
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java
new file mode 100644
index 00000000..5588b288
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/JpqlDemoApplication.java
@@ -0,0 +1,13 @@
+package ru.otus.example.jpql_demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class JpqlDemoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JpqlDemoApplication.class, args);
+ }
+
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java
new file mode 100644
index 00000000..29078c2f
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/CitySalary.java
@@ -0,0 +1,15 @@
+package ru.otus.example.jpql_demo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CitySalary {
+ private String city;
+ private Double salary;
+
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java
new file mode 100644
index 00000000..7f73ba5c
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/dto/EmployeeProjects.java
@@ -0,0 +1,16 @@
+package ru.otus.example.jpql_demo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import ru.otus.example.jpql_demo.models.Employee;
+
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class EmployeeProjects {
+ private Employee employee;
+ private long projectsCount;
+
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java
new file mode 100644
index 00000000..96a03d58
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Address.java
@@ -0,0 +1,24 @@
+package ru.otus.example.jpql_demo.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "addresses")
+public class Address {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @Column(name = "city")
+ private String city;
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java
new file mode 100644
index 00000000..79110620
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Department.java
@@ -0,0 +1,21 @@
+package ru.otus.example.jpql_demo.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "departments")
+public class Department {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @Column
+ private String name;
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java
new file mode 100644
index 00000000..0bcd8123
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Employee.java
@@ -0,0 +1,53 @@
+package ru.otus.example.jpql_demo.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "employees")
+public class Employee {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @Column(name = "first_name")
+ private String firstName;
+
+ @Column(name = "last_name")
+ private String lastName;
+
+ @Column(name = "salary")
+ private BigDecimal salary;
+
+ @ManyToOne
+ @JoinColumn(name = "department_id", referencedColumnName = "id")
+ private Department department;
+
+ @ManyToOne
+ @JoinColumn(name = "address_id", referencedColumnName = "id")
+ private Address address;
+
+ @BatchSize(size = 100)
+ @ManyToMany
+ @JoinTable(name = "employees_projects",
+ joinColumns = @JoinColumn(name = "employee_id", referencedColumnName = "id"),
+ inverseJoinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"))
+ private List projects;
+
+
+ public Employee(String firstName, String lastName) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java
new file mode 100644
index 00000000..f22e4242
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/models/Project.java
@@ -0,0 +1,21 @@
+package ru.otus.example.jpql_demo.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "projects")
+public class Project {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @Column(name = "name")
+ private String name;
+}
diff --git a/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java
new file mode 100644
index 00000000..3c00881c
--- /dev/null
+++ b/examples/jpql-demo/src/main/java/ru/otus/example/jpql_demo/repositories/EmployeeRepository.java
@@ -0,0 +1,49 @@
+package ru.otus.example.jpql_demo.repositories;
+
+import ru.otus.example.jpql_demo.dto.CitySalary;
+import ru.otus.example.jpql_demo.dto.EmployeeProjects;
+import ru.otus.example.jpql_demo.models.Employee;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Optional;
+
+public interface EmployeeRepository {
+
+ List findAll();
+ Optional findEmployeeById(long id);
+ List findAllEmployeesWithSalaryOver100000();
+ List findEmployeesFirstNames();
+ List