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 4 和 Introduction 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.
这需要我们创建一个带有JpaEntityInformation和EntityManager参数的构造函数,调用父类的构造函数。
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上找到。