Sometimes, we need to customize the Repository to achieve some special business scenarios.
1, a single custom Repository
1.1, a first segment interface and implementation (the default implementation of the interface to be used for the Impl suffix itself does not depend achieve spring-data, may be a conventional spring-bean, the bean can be injected into the other, e.g. JdbcTemplate).
/** * @author caofanqi */ public interface StudentRepositoryCustomJdbc { List<Student> findStudentByJdbcName(String name); } /** * Default To Impl end * @author caofanqi */ public class StudentRepositoryCustomJdbcImpl implements StudentRepositoryCustomJdbc { @Resource private JdbcTemplate jdbcTemplate; @Override public List<Student> findStudentByJdbcName(String name) { String sql = "SELECT * FROM cfq_jpa_student WHERE name = " + "'" + name + "'"; return jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Student.class)); } }
1.2 Repository inherit their custom interface, you can use the expanded functions.
/** * Inheritance jpa the repository, and your own custom extensions * @author caofanqi */ public interface StudentRepository extends JpaRepositoryImplementation<Student,Long>, StudentRepositoryCustomJdbc { }
1.3, the test is as follows:
@BeforeEach void setup(){ Student s1 = Student.builder().name("张三").age(23).build(); Student s2 = Student.builder().name("李四").age(24).build(); Student s3 = Student.builder().name("王五").age(25).build(); studentRepository.saveAll(Lists.newArrayList(s1,s2,s3)); } @Test void testFindStudentByJdbcName(){ List<Student> list = studentRepository.findStudentByJdbcName("张三"); list.forEach(s -> System.out.println(s.getName())); }
1.4, Print Console:
Hibernate: insert into cfq_jpa_student (age, name) values (?, ?) Hibernate: insert into cfq_jpa_student (age, name) values (?, ?) Hibernate: insert into cfq_jpa_student (age, name) values (?, ?) Joe Smith
1.5, you can have multiple custom extensions. Customize a higher priority than spring-data to us.
/** * Inheritance jpa the repository, and your own custom extensions * @author caofanqi */ public interface StudentRepository extends JpaRepositoryImplementation<Student,Long>, StudentRepositoryCustomJdbc,StudentRepositoryCustom<Student,Long> { }
/** * Custom student function * * @author caofanqi */ public interface StudentRepositoryCustom<T,ID> { Optional<T> findById(ID id); } /** * Custom implementation repository function * * @author caofnqi */ @ slf4j public class StudentRepositoryCustomImpl<T,ID> implements StudentRepositoryCustom<T,ID> { @PersistenceContext private EntityManager entityManager; @Override public Optional<T> findById(ID id) { log.info ( "Custom the findById" ); T t = (T) entityManager.find(Student.class, id); return Optional.of(t); } }
1.6, it can repositoryImplementationPostfix property @EnableJpaRepositories custom suffix, the default is Impl.
/** * Start class * @Author caofanqi * / @SpringBootApplication @EnableAsync @EnableJpaRepositories(repositoryImplementationPostfix = "MyPostfix") public class StudySpringDataJpaApplication { public static void main(String[] args) { SpringApplication.run(StudySpringDataJpaApplication.class, args); } }
2, custom BaseRepository
2.1, the proxy class SpringDataJpa provides us with the fact SimpleJpaRepository.
2.2, if we want to save all the operations are carried out Repository log, we can customize BaseRepository, to act as a proxy class. (Can also be a logical delete scenes)
2.2.1, custom baseRepository
/** * Custom base Repository * * @Author caofanqi * / @ slf4j public class MyRepositoryImpl<T,ID> extends SimpleJpaRepository<T,ID> { private final EntityManager entityManager; MyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; } @Override public <S extends T> S save(S entity) { S save = super.save(entity); log.info("保存了:{}",save); return save; } }
2.2.2 to inform the Spring-Data-Jpa use our custom baseRepository
/** * Start class * @Author caofanqi * / @SpringBootApplication @EnableAsync @EnableJpaRepositories( /*queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND*/ /* ,repositoryImplementationPostfix = "MyPostfix",*/ repositoryBaseClass = MyRepositoryImpl.class) public class StudySpringDataJpaApplication { public static void main(String[] args) { SpringApplication.run(StudySpringDataJpaApplication.class, args); } }
2.2.3 Test Method testSave again, as follows
3, entityManager perform complex sql native returned DTO
When using a method derived query and @Query notes queries, we can use the projector to object-oriented programming, but when executing complex native sql sql use entityManager, how to return the entity it? as follows:
3.1、DTO
/** * Results entityManager map used, with the need to set a reference method is not a constructor, which is not the same as the projection * @Author caofanqi * / @Data @NoArgsConstructor @AllArgsConstructor public class StudentAgeAndAgeCountDTO { private Integer age; private Long ageCount; }
3.2、查询方法
public List<StudentAgeAndAgeCountDTO> findCountGroupByAge(){ /* *sql可以是更复杂的 */ String sql = "SELECT age,count(*) AS ageCount FROM cfq_jpa_student GROUP BY age "; Query nativeQuery = entityManager.createNativeQuery(sql); nativeQuery.unwrap(NativeQuery.class) //设置类型 .addScalar("age", StandardBasicTypes.INTEGER) .addScalar("ageCount",StandardBasicTypes.LONG) //设置返回bean .setResultTransformer(Transformers.aliasToBean(StudentAgeAndAgeCountDTO.class)); return nativeQuery.getResultList(); }
3.3、测试及结果
源码地址:https://github.com/caofanqi/study-spring-data-jpa