Spring Data JPA – Adding a Method in All Repositories – Spring Data JPA – 在所有存储库中添加一个方法

最后修改: 2017年 10月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Spring Data makes the process of working with entities a lot easier by merely defining repository interfaces. These come with a set of pre-defined methods and allow the possibility of adding custom methods in each interface.

Spring Data仅仅通过定义存储库接口,就使与实体打交道的过程变得简单了许多。这些接口带有一组预定义的方法,并允许在每个接口中添加自定义方法。

However, if we want to add a custom method that’s available in all the repositories, the process is a bit more complex. So, that’s what we’ll explore here with Spring Data JPA.

然而,如果我们想添加一个在所有存储库中都可用的自定义方法,这个过程就有点复杂了。所以,这就是我们在这里要探讨的Spring Data JPA。

For more information on configuring and using Spring Data JPA, check out our previous articles: Guide to Hibernate with Spring 4 and Introduction to Spring Data JPA.

有关配置和使用Spring Data JPA的更多信息,请查看我们以前的文章。Guide to Hibernate with Spring 4Introduction to Spring Data JPA

2. Defining a Base Repository Interface

2.定义基础存储库接口

First, we have to create a new interface that declares our custom method:

首先,我们必须创建一个新的接口,声明我们的自定义方法。

@NoRepositoryBean
public interface ExtendedRepository<T, ID extends Serializable> 
  extends JpaRepository<T, ID> {
 
    public List<T> findByAttributeContainsText(String attributeName, String text);
}

Our interface extends the JpaRepository interface so that we’ll benefit from all the standard behavior.

我们的接口扩展了JpaRepository接口,因此我们将受益于所有的标准行为。

You’ll also notice we added the @NoRepositoryBean annotation. This is necessary because otherwise, the default Spring behavior is to create an implementation for all subinterfaces of Repository.

你还会注意到我们添加了@NoRepositoryBean注释。这是必要的,因为否则的话,Spring的默认行为是为Repository的所有子接口创建一个实现。

Here, we’ll want to provide our implementation that should be used, as this is only an interface meant to be extended by the actual entity-specific DAO interfaces.

在这里,我们要提供我们应该使用的实现,因为这只是一个接口,旨在被实际的实体特定的DAO接口所扩展。

3. Implementing a Base Class

3.实现一个基类

Next, we’ll provide our implementation of the ExtendedRepository interface:

接下来,我们将提供我们对ExtendedRepository接口的实现。

public class ExtendedRepositoryImpl<T, ID extends Serializable>
  extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {
    
    private EntityManager entityManager;

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

    // ...
}

This class extends the SimpleJpaRepository class, which is the default class that Spring uses to provide implementations for repository interfaces.

该类扩展了SimpleJpaRepository类,该类是Spring用来为存储库接口提供实现的默认类。

This requires that we create a constructor with the JpaEntityInformation and EntityManager parameters that calls the constructor from the parent class.

这需要我们创建一个带有JpaEntityInformationEntityManager参数的构造函数,调用父类的构造函数。

We also need the EntityManager property to use in our custom method.

我们还需要EntityManager属性,以便在我们的自定义方法中使用。

Also, we have to implement the custom method inherited from the ExtendedRepository interface:

同时,我们必须实现从ExtendedRepository接口继承的自定义方法。

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

Here, the findByAttributeContainsText() method searches for all the objects of type T that have a particular attribute which contains the String value given as parameter.

在这里,findByAttributeContainsText()方法搜索所有具有特定属性的T类型的对象,该属性包含作为参数的String值。

4. JPA Configuration

4.JPA配置

To tell Spring to use our custom class instead of the default one for building repository implementations, we can use the repositoryBaseClass attribute:

为了告诉Spring使用我们的自定义类而不是默认的类来构建版本库实现,我们可以使用repositoryBaseClass属性

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

5. Creating an Entity Repository

5.创建一个实体仓库

Next, let’s see how we can use our new interface.

接下来,让我们看看如何使用我们的新界面。

First, let’s add a simple Student entity:

首先,让我们添加一个简单的Student实体。

@Entity
public class Student {

    @Id
    private long id;
    private String name;
    
    // standard constructor, getters, setters
}

Then, we can create a DAO for the Student entity which extends the ExtendedRepository interface:

然后,我们可以为Student实体创建一个DAO,它扩展了ExtendedRepository接口。

public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}

And that’s it! Now our implementation will have the custom findByAttributeContainsText() method.

就这样了!现在我们的实现将拥有自定义的findByAttributeContainsText()方法。

Similarly, any interface we define by extending the ExtendedRepository interface will have the same method.

同样地,我们通过扩展ExtendedRepository接口定义的任何接口都会有相同的方法。

6. Testing the Repository

6.测试存储库

Let’s create a JUnit test that shows the custom method in action:

让我们创建一个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<Student> students 
          = extendedStudentRepository.findByAttributeContainsText("name", "john");
 
        assertEquals("size incorrect", 2, students.size());        
    }
}

The test uses the extendedStudentRepository bean first to create 3 Student records. Then, the findByAttributeContains() method is called to find all students whose name contains the text “john”.

该测试首先使用extendedStudentRepositorybean来创建3条学生记录。然后,调用findByAttributeContains()方法来查找所有名字中包含 “john “的学生。

The ExtendedStudentRepository class can use both standard methods like save() and the custom method we added.

ExtendedStudentRepository类可以使用标准方法,如save()和我们添加的自定义方法。

7. Conclusion

7.结论

In this quick article, we’ve shown how we can add a custom method to all repositories in Spring Data JPA.

在这篇快速文章中,我们展示了如何在Spring Data JPA的所有存储库中添加一个自定义方法。

The full source code for the examples can be found over on GitHub.

示例的完整源代码可以在GitHub上找到