Spring Data довольно удобен и ускоряет разработку, избегая стандартного кода. Однако в некоторых случаях запросов аннотации недостаточно для пользовательских функций, которые вы, возможно, захотите достичь.
Поэтому данные Spring позволяют нам добавлять собственные методы в репозиторий данных Spring. Я буду использовать ту же структуру проекта из предыдущего поста в блоге.
У нас есть организация под названием Сотрудник
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
package com.gkatzioura.springdata.jpa.persistence.entity;import javax.persistence.*;/** * Created by gkatzioura on 6/2/16. */@Entity@Table(name = "employee", schema="spring_data_jpa_example")public class Employee { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @Column(name = "firstname") private String firstName; @Column(name = "lastname") private String lastname; @Column(name = "email") private String email; @Column(name = "age") private Integer age; @Column(name = "salary") private Integer salary; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getSalary() { return salary; } public void setSalary(Integer salary) { this.salary = salary; }} |
И хранилище данных Spring
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
package com.gkatzioura.springdata.jpa.persistence.repository;import com.gkatzioura.springdata.jpa.persistence.entity.Employee;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;/** * Created by gkatzioura on 6/2/16. */@Repositorypublic interface EmployeeRepository extends JpaRepository<Employee,Long>{} |
Предположим, что мы хотим добавить некоторые пользовательские функции sql, например, запрос с помощью оператора LIKE и соединение с таблицей, которая не отображается как сущность.
Это только для демонстрационных целей. Для вашего проекта у вас может быть лучшая схема. Плюс пружинные данные поставляются с готовой функциональностью для похожих операторов, посмотрите EndingWith, Conisting, StartingWith .
Мы создадим бонусную таблицу и добавим ссылку на таблицу сотрудников.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
set schema 'spring_data_jpa_example';create table bonus( id serial primary key, employee_id integer, amount real, foreign key (employee_id) references employee (id), unique (employee_id) );insert into bonus( employee_id, amount)VALUES(1, 100); |
SQL-запрос, который мы хотим реализовать, будет запрашивать сотрудников, чье имя начинается с указанного текста и бонуса, превышающего определенную сумму. В jdbc мы должны передать нашу переменную конкатенированную с символом «%».
Так что нам нужен собственный запрос jpa, как этот
|
1
2
3
4
5
6
|
Query query = entityManager.createNativeQuery("select e.* from spring_data_jpa_example.bonus b, spring_data_jpa_example.employee e\n" + "where e.id = b.employee_id " + "and e.firstname LIKE ? " + "and b.amount> ? ", Employee.class); query.setParameter(1, firstName + "%"); query.setParameter(2, bonusAmount); |
Чтобы добавить эту функциональность в наш репозиторий данных Spring, мы должны добавить интерфейс. Наш интерфейс должен следовать соглашению об именах $ {Original Repository name} Custom. Поэтому интерфейс, описывающий наши пользовательские функции, должен быть
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
package com.gkatzioura.springdata.jpa.persistence.repository;import com.gkatzioura.springdata.jpa.persistence.entity.Employee;import java.util.List;/** * Created by gkatzioura on 6/3/16. */public interface EmployeeRepositoryCustom { List<Employee> getFirstNamesLikeAndBonusBigger(String firstName, Double bonusAmount);} |
И реализация должна быть
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.gkatzioura.springdata.jpa.persistence.repository;import com.gkatzioura.springdata.jpa.persistence.entity.Employee;import org.springframework.stereotype.Repository;import org.springframework.transaction.annotation.Transactional;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.Query;import java.util.List;/** * Created by gkatzioura on 6/3/16. */@Repository@Transactional(readOnly = true)public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom { @PersistenceContext EntityManager entityManager; @Override public List<Employee> getFirstNamesLikeAndBonusBigger(String firstName, Double bonusAmount) { Query query = entityManager.createNativeQuery("select e.* from spring_data_jpa_example.bonus b, spring_data_jpa_example.employee e\n" + "where e.id = b.employee_id " + "and e.firstname LIKE ? " + "and b.amount> ? ", Employee.class); query.setParameter(1, firstName + "%"); query.setParameter(2, bonusAmount); return query.getResultList(); }} |
И мы должны изменить наш исходный репозиторий данных Spring, чтобы наследовать пользовательские функции.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
package com.gkatzioura.springdata.jpa.persistence.repository;import com.gkatzioura.springdata.jpa.persistence.entity.Employee;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;/** * Created by gkatzioura on 6/2/16. */@Repositorypublic interface EmployeeRepository extends JpaRepository<Employee,Long>, EmployeeRepositoryCustom {} |
Похоже, хороший способ композиции. Теперь давайте добавим метод в контроллер, который будет вызывать этот пользовательский метод
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.gkatzioura.springdata.jpa.controller; import com.gkatzioura.springdata.jpa.persistence.entity.Employee; import com.gkatzioura.springdata.jpa.persistence.repository.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List;/** * Created by gkatzioura on 6/2/16. */@RestControllerpublic class TestController { @Autowired private EmployeeRepository employeeRepository; @RequestMapping("/employee") public List<Employee> getTest() { return employeeRepository.findAll(); } @RequestMapping("/employee/filter") public List<Employee> getFiltered(String firstName,@RequestParam(defaultValue = "0") Double bonusAmount) { return employeeRepository.getFirstNamesLikeAndBonusBigger(firstName,bonusAmount); }} |
Исходный код можно найти на github .
| Ссылка: | Добавьте пользовательскую функциональность в репозиторий данных Spring от нашего партнера по JCG Эммануила Гкациоураса в блоге gkatzioura . |