Spring Data JPA - Добавление метода во все репозитории

Spring Data JPA - добавление метода во все репозитории

1. обзор

Spring Data значительно упрощает процесс работы с сущностями, просто определяя интерфейсы репозитория. Они поставляются с набором предопределенных методов и позволяют добавлять пользовательские методы в каждый интерфейс.

Однако если мы хотим добавить собственный метод, доступный во всех репозиториях, процесс будет немного сложнее. Итак, это то, что мы исследуем здесь с помощью Spring Data JPA.

Для получения дополнительной информации о настройке и использовании Spring Data JPA ознакомьтесь с нашими предыдущими статьями:Guide to Hibernate with Spring 4 иIntroduction to Spring Data JPA.

2. Определение базового интерфейса репозитория

Сначала мы должны создать новый интерфейс, который объявляет наш пользовательский метод:

@NoRepositoryBean
public interface ExtendedRepository
  extends JpaRepository {

    public List findByAttributeContainsText(String attributeName, String text);
}

Наш интерфейс расширяет интерфейсJpaRepository, поэтому мы можем воспользоваться всеми преимуществами стандартного поведения.

Вы также заметите, что мы добавили аннотацию@NoRepositoryBean. Это необходимо, потому что в противном случае поведение Spring по умолчанию заключается в создании реализации для всех подинтерфейсовRepository.

Здесь мы хотим предоставить нашу реализацию, которую следует использовать, поскольку это только интерфейс, предназначенный для расширения фактическими интерфейсами DAO, зависящими от сущности.

3. Реализация базового класса

Далее мы представим нашу реализацию интерфейсаExtendedRepository:

public class ExtendedRepositoryImpl
  extends SimpleJpaRepository implements ExtendedRepository {

    private EntityManager entityManager;

    public ExtendedRepositoryImpl(JpaEntityInformation
      entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    // ...
}

Этот класс расширяет классSimpleJpaRepository, который является классом по умолчанию, который Spring использует для предоставления реализаций интерфейсов репозитория.

Для этого необходимо создать конструктор с параметрамиJpaEntityInformation иEntityManager, который вызывает конструктор из родительского класса.

Нам также нужно свойствоEntityManager для использования в нашем пользовательском методе.

Также мы должны реализовать собственный метод, унаследованный от интерфейсаExtendedRepository:

@Transactional
public List findByAttributeContainsText(String attributeName, String text) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery cQuery = builder.createQuery(getDomainClass());
    Root root = cQuery.from(getDomainClass());
    cQuery
      .select(root)
      .where(builder
        .like(root.get(attributeName), "%" + text + "%"));
    TypedQuery query = entityManager.createQuery(cQuery);
    return query.getResultList();
}

Здесь методfindByAttributeContainsText() ищет все объекты типа T, которые имеют конкретный атрибут, который содержит значениеString, указанное в качестве параметра.

4. Конфигурация JPA

Чтобы сообщить Spring использовать наш собственный класс вместо класса по умолчанию для создания реализаций репозитория,we can use the repositoryBaseClass attribute:

@Configuration
@EnableJpaRepositories(basePackages = "org.example.persistence.dao",
  repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
    // additional JPA Configuration
}

5. Создание репозитория сущностей

Затем давайте посмотрим, как мы можем использовать наш новый интерфейс.

Во-первых, давайте добавим простую сущностьStudent:

@Entity
public class Student {

    @Id
    private long id;
    private String name;

    // standard constructor, getters, setters
}

Затем мы можем создать DAO для объектаStudent, который расширяет интерфейсExtendedRepository:

public interface ExtendedStudentRepository extends ExtendedRepository {
}

Вот и все! Теперь наша реализация будет иметь собственный методfindByAttributeContainsText().

Точно так же любой интерфейс, который мы определяем путем расширения интерфейсаExtendedRepository, будет иметь тот же метод.

6. Тестирование репозитория

Давайте создадим тестJUnit, который покажет настраиваемый метод в действии:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { StudentJPAH2Config.class })
public class ExtendedStudentRepositoryIntegrationTest {

    @Resource
    private ExtendedStudentRepository extendedStudentRepository;

    @Before
    public void setup() {
        Student student = new Student(1, "john");
        extendedStudentRepository.save(student);
        Student student2 = new Student(2, "johnson");
        extendedStudentRepository.save(student2);
        Student student3 = new Student(3, "tom");
        extendedStudentRepository.save(student3);
    }

    @Test
    public void givenStudents_whenFindByName_thenOk(){
        List students
          = extendedStudentRepository.findByAttributeContainsText("name", "john");

        assertEquals("size incorrect", 2, students.size());
    }
}

В тесте сначала используется bean-компонентextendedStudentRepository для создания трех записей Student. Затем вызывается методfindByAttributeContains(), чтобы найти всех студентов, имя которых содержит текст «john».

КлассExtendedStudentRepository может использовать как стандартные методы, такие какsave(), так и добавленный нами собственный метод.

7. Заключение

В этой быстрой статье мы показали, как добавить собственный метод ко всем репозиториям в Spring Data JPA.

Полный исходный код примеров можно найти вover on GitHub.