بيانات الربيع jpa

في المقالة سوف أصف استخدام Spring Data.

Spring Data عبارة عن آلية ملائمة إضافية للتفاعل مع كيانات قواعد البيانات ، وتنظيمها في مستودع ، واستعادة البيانات ، وتغييرها ، في بعض الحالات ، ستكون كافية لإعلان واجهة وطريقة فيها ، دون تنفيذ.

المحتوى:

  1. مستودع الربيع
  2. طلب طرق من اسم الطريقة
  3. التكوين والإعداد
  4. معالجة المعلمة الخاصة
  5. تطبيقات مستودع مخصص
  6. مستودع قاعدة مخصصة
  7. طرق الاستعلام - الاستعلام


1. مستودع الربيع


المفهوم الأساسي في Spring Data هو المستودع. هذه هي عدة واجهات تستخدم JPA Entity للتفاعل معها. لذلك على سبيل المثال واجهة
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>
يوفر عمليات أساسية للبحث عن البيانات وحفظها وحذفها (عمليات CRUD)

 T save(T entity); Optional findById(ID primaryKey); void delete(T entity); 

وغيرها من العمليات.

هناك تجريدات أخرى ، مثل PagingAndSortingRepository.

أي إذا كانت القائمة التي توفرها الواجهة كافية للتفاعل مع الكيان ، يمكنك بعد ذلك توسيع الواجهة الأساسية لكيانك مباشرةً ، مع استكمالها بطرق الاستعلام الخاصة بك وتنفيذ العمليات. الآن سأعرض بإيجاز تلك الخطوات اللازمة لأبسط الحالات (دون تشتيت حتى الآن من خلال التكوين ، ORM ، قاعدة البيانات).

1. إنشاء كيان

 @Entity @Table(name = "EMPLOYEES") public class Employees { private Long employeeId; private String firstName; private String lastName; private String email; // . . . 

2. موروثة من إحدى واجهات Spring Data ، على سبيل المثال من CrudRepository

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> 

3. استخدم في العميل (الخدمة) واجهة جديدة لعمليات البيانات

 @Service public class EmployeesDataService { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() { Optional<Employees> employeesOptional = employeesCrudRepository.findById(127L); //.... } 

أنا هنا استخدمت طريقة findById الجاهزة . أي بسرعة وسهولة ، دون تنفيذ ، نحصل على قائمة جاهزة من العمليات من CrudRepository:

  S save(S var1); Iterable<S> saveAll(Iterable<S> var1); Optional<T> findById(ID var1); boolean existsById(ID var1); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable<? extends T> var1); void deleteAll(); 

من الواضح أن هذه القائمة على الأرجح لن تكون كافية للتفاعل مع الكيان ، ويمكنك هنا توسيع الواجهة باستخدام طرق استعلام إضافية.

2. طرق الاستعلام من اسم الأسلوب


يمكن بناء الطلبات إلى الكيان مباشرة من اسم الطريقة. للقيام بذلك ، يتم العثور على ... حسب ، وقراءة ... حسب ، استعلام ... حسب ، العد ... حسب ، والحصول على ... باستخدام البادئات ، بالإضافة إلى بادئة الطريقة ، يبدأ في تحليل باقيها. الجملة التمهيدية قد تحتوي على تعبيرات إضافية ، على سبيل المثال ، مميزة. بعد ذلك ، يعمل الأول حسب الفاصل للإشارة إلى بداية المعايير الفعلية. يمكنك تحديد شروط خصائص الكيان ودمجها باستخدام And و. أمثلة

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { //    firstName And LastName Optional<Employees> findByFirstNameAndLastName(String firstName, String lastName); //   5  FirstName       FirstName List<Employees> findFirst5ByFirstNameStartsWithOrderByFirstName(String firstNameStartsWith); 

تعرّف الوثائق القائمة بأكملها وقواعد كتابة الطريقة. يمكن أن تكون النتيجة كيان T ، اختياري ، قائمة ، دفق. في بيئة التطوير ، مثل Idea ، هناك تلميح لكتابة طرق الاستعلام.

الصورة
يكفي تحديد طريقة بهذه الطريقة ، دون تنفيذ ، وسيقوم Spring بإعداد طلب للكيان.

 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() { Optional<Employees> employeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov"); 

3. التكوين والإعداد


المشروع بأكمله متاح على جيثب
github DemoSpringData

هنا سأتطرق فقط إلى بعض الميزات.

يتم تعريف معاملة TransactionManager و dataSource و entityManagerFactory في context.xml. من المهم الإشارة في ذلك أيضًا

 <jpa:repositories base-package="com.example.demoSpringData.repositories"/> 

المسار حيث يتم تعريف المستودعات.

تم تكوين EntityManagerFactory للعمل مع Hibernate ORM ، وهو بدوره مع قاعدة بيانات Oracle XE ، وهنا توجد خيارات أخرى ممكنة ، في السياق. xml كل هذا مرئي. ملف بوم لديه كل التبعيات.

4. معالجة خاصة من المعلمات


في طرق الاستعلام ، في المعلمات الخاصة بهم ، يمكنك استخدام المعلمات الخاصة Pageable ، Sort ، وكذلك القيود Top and First.

على سبيل المثال ، على هذا النحو ، يمكنك أن تأخذ الصفحة الثانية (الفهرس بـ -0) ، وحجم ثلاثة عناصر وفرزها حسب الاسم الأول ، وبعد تحديد المعلمة Pageable في طريقة المستودع ، سيتم استخدام المعايير من اسم الطريقة - "البحث حسب الاسم الأول يبدأ بـ٪„

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { List<Employees> findByFirstNameStartsWith(String firstNameStartsWith, Pageable page); //.... } //   @Test @Transactional public void testFindByFirstNameStartsWithOrderByFirstNamePage() { List<Employees> list = employeesCrudRepository .findByFirstNameStartsWith("A", PageRequest.of(1,3, Sort.by("firstName"))); list.forEach(e -> System.out.println(e.getFirstName() + " " +e.getLastName())); } 

5. تطبيقات مخصصة للمستودع


افترض أنك بحاجة إلى طريقة في المخزون لا يمكن وصفها باسم الطريقة ، ثم يمكنك تنفيذها باستخدام الواجهة الخاصة بك وفئة التنفيذ الخاصة بها. في المثال أدناه ، سأضيف إلى المستودع طريقة للحصول على موظفين بأجر أقصى.

تعلن واجهة

 public interface CustomizedEmployees<T> { List<T> getEmployeesMaxSalary(); } 

تنفذ الواجهة. باستخدام HQL (SQL) أحصل على موظفين بأجر أقصى ، هناك تطبيقات أخرى ممكنة.

 public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Override public List getEmployeesMaxSalary() { return em.createQuery("from Employees where salary = (select max(salary) from Employees )", Employees.class) .getResultList(); } } 

وأيضًا توسيع مستودعات مستودع Crud مع الموظفين المخصصين.

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> 

هناك ميزة واحدة مهمة هنا. يجب أن تنتهي واجهة تنفيذ الفصل (postfix) على Impl ، أو في التكوين تحتاج إلى وضع postfix الخاص بك

 <repositories base-package="com.repository" repository-impl-postfix="MyPostfix" /> 

التحقق من تشغيل هذه الطريقة من خلال المستودع

 public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() { List<Employees> employees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); } 

حالة أخرى عندما يكون من الضروري تغيير سلوك طريقة موجودة في واجهة Spring ، على سبيل المثال ، حذف في CrudRepository ، أحتاج أنه بدلاً من الحذف من قاعدة البيانات ، يتم تعيين علامة على الحذف. هذه التقنية هي بالضبط نفس الشيء. أدناه مثال:

 public interface CustomizedEmployees<T> { void delete(T entity); // ... } //  CustomizedEmployees public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Transactional @Override public void delete(Object entity) { Employees employees = (Employees) entity; employees.setDeleted(true); em.persist(employees); } 

الآن ، إذا قمت بالاتصال بحذف في staffCrudRepository ، فسيتم تعليم الكائن فقط على أنه محذوف.

6. مستودع قاعدة المستخدم


في المثال السابق ، أوضحت كيفية إعادة تحديد مستودع الحذف لكيان في Crud ، ولكن إذا كنت بحاجة إلى القيام بذلك لجميع كيانات المشروع ، فقم بجعل الواجهة الخاصة بك غير جيدة لكل ... ثم في بيانات Spring ، يمكنك تكوين مستودعك الأساسي. للقيام بذلك:
يتم الإعلان عن واجهة وهي طريقة للتغلب عليها (أو مشتركة بين جميع كيانات المشروع). هنا ، بالنسبة لجميع الكيانات الخاصة بي ، قمت بتقديم واجهة BaseEntity الخاصة بي (هذا ليس ضروريًا) ، من أجل راحة استدعاء الأساليب الشائعة ، تتوافق أساليبها مع أساليب الكيان.

 public interface BaseEntity { Boolean getDeleted(); void setDeleted(Boolean deleted); } //  Employees @Entity @Table(name = "EMPLOYEES") public class Employees implements BaseEntity { private Boolean deleted; @Override public Boolean getDeleted() { return deleted; } @Override public void setDeleted(Boolean deleted) { this.deleted = deleted; } //    @NoRepositoryBean public interface BaseRepository <T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID> { void delete(T entity); } //    BaseRepository public class BaseRepositoryImpl <T extends BaseEntity, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> { private final EntityManager entityManager; public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; } @Transactional @Override public void delete(BaseEntity entity) { entity.setDeleted(true); entityManager.persist(entity); } } 

في التكوين ، ستحتاج إلى تحديد مستودع التخزين الأساسي هذا ، وسيكون مشتركًا في جميع مستودعات المشروع

  <jpa:repositories base-package="com.example.demoSpringData.repositories" base-class="com.example.demoSpringData.BaseRepositoryImpl"/> 

الآن يجب توسيع مستودع الموظفين (وغيرها) من BaseRepository واستخدامه بالفعل في العميل.

 public interface EmployeesBaseRepository extends BaseRepository <Employees, Long> { // ... } 

فحص EmployeesBaseRepository

 public class DemoSpringDataApplicationTests { @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() { Employees employees = new Employees(); employees.setLastName("Ivanov"); // Query by Example (QBE) Example<Employees> example = Example.of(employees); Optional<Employees> employeesOptional = employeesBaseRepository.findOne(example); employeesOptional.ifPresent(employeesBaseRepository::delete); } 

الآن ، كما كان من قبل ، سيتم تمييز الكائن على أنه محذوف ، وسيتم تنفيذ ذلك لجميع الكيانات التي تعمل على توسيع واجهة BaseRepository. في المثال ، تم تطبيق طريقة البحث - Query by Example (QBE) ، ولن أصفها هنا ، يوضح المثال ما تقوم به ، بسيط ومريح.

7. طرق الاستعلام - الاستعلام


في وقت سابق ، كتبت أنه إذا كنت بحاجة إلى طريقة محددة أو تنفيذها ، والتي لا يمكن وصفها باستخدام اسم الطريقة ، فيمكن القيام بذلك من خلال بعض الواجهات المخصصة (CustomEmployees) وإجراء تطبيق حسابي. ويمكنك الذهاب في الاتجاه الآخر ، من خلال الإشارة إلى الاستعلام (HQL أو SQL) ، وكيفية حساب هذه الوظيفة.
على سبيل المثال الخاص بي مع getEmployeesMaxSalary ، يكون خيار التنفيذ هذا أبسط. أنا سوف تعقيد ذلك مع المعلمة إدخال الراتب. أي يكفي أن تعلن طريقة الحساب والطلب في الواجهة.

 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> { @Query("select e from Employees e where e.salary > :salary") List<Employees> findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort); // ... } 

التحقق

 @Test @Transactional public void testFindEmployeesWithMoreThanSalary() { List<Employees> employees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName")); 

سأشير فقط إلى أنه يمكن أن يكون هناك تعديل الطلبات ، لهذا إضافة تعليق توضيحي إضافي @ @ لهم

 @Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId); 

تتمثل إحدى الميزات الرائعة لتعليقات Query في استبدال نوع مجال الكيان في الاستعلام باستخدام القالب # {# entityName} ، من خلال تعبيرات SpEL.

لذلك ، على سبيل المثال ، في المثال الافتراضي الخاص بي ، عندما أحتاج إلى الحصول على علامة "المحذوفة" لجميع الكيانات ، سأقوم بإنشاء واجهة أساسية مع طريقة للحصول على قائمة الكائنات مع علامة "حذف" أو "نشط"

 @NoRepositoryBean public interface ParentEntityRepository<T> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.deleted = ?1") List<T> findMarked(Boolean deleted); } 

علاوة على ذلك ، يمكن تمديد جميع مستودعات الكيانات منه. واجهات غير مستودعات ، ولكن تقع في مجلد التكوين "الحزمة الأساسية" ، علقNoRepositoryBean.

مستودع الموظفين

 @Repository public interface EmployeesEntityRepository extends ParentEntityRepository <Employees> { } 

الآن عند تنفيذ الطلب ، سيتم استبدال اسم الكيان T في نص الطلب لمستودع محدد يمتد ParentEntityRepository ، في هذه الحالة الموظفون.

تحقق

 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() { List<Employees> employeesMarked = employeesEntityRepository.findMarked(true); // ... 

المواد
بيانات الربيع JPA - الوثائق المرجعية
مشروع على جيثب .

Source: https://habr.com/ru/post/ar435114/


All Articles