Занятие №9
Spring Data
Губайдулин
Константин
О себе
Губайдулин Константин
Опыт работы:
Технологии:
Личное:
Вспомним прошлое занятие по JPA и Hibernate.
Чтобы работать с данными, мы должны:
Вы просто пишете интерфейс репозитория
И все..
dependencies {
    // ...
	implementation
       'org.springframework.boot:spring-boot-starter-data-jpa'
    // ...
}
@Entity
public class Book {
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column
    private String title;
    @Column
    private String description;
    @Column
    private Integer year;
}public interface BookRepository 
     extends CrudRepository<Book, Long> {
}
Domain Drive Design см. здесь
@SpringBootApplication
@EnableJpaRepositories(basePackages="pro.sisit.unit9.data")
public class SpringDataApplication {public interface CrudRepository<T, ID>
	extends Repository<T, ID> {
  <S extends T> S save(S entity);
  
  Optional<T> findById(ID primaryKey);
  Iterable<T> findAll();               
  long count();                        
  void delete(T entity);               
  boolean existsById(ID primaryKey);   
  // … more functionality omitted.
}Create Read Update Delete aka CRUD
public class BookServiceImpl implements BookService {
    private final BookRepository bookRepository;
    @Override
    public void save(Book book) {
        bookRepository.save(book);
    }
    @Override
    public Optional<Book> findById(Long id) {
        return bookRepository.findById(id);
    }
}@Test
public void testSave() {
    Book book = new Book();
    book.setTitle("Буратино");
    book.setYear(1936);
    bookRepository.save(book);
    
    boolean founded = false;
    for (Book iteratedBook : bookRepository.findAll()) {
        if (iteratedBook.getTitle().equals("Буратино")
            && iteratedBook.getId() > 0) {
           founded = true;
        }
    }
    Assert.assertTrue(founded);
}public interface BookRepository 
        extends CrudRepository<Book, Long> {
    List<Book> findByYear(int year);
}Определяем метод запроса, просто объявив сигнатуру этого метода
@Test
public void testFindByYear() {
    Assert.assertTrue(
    bookRepository.findByYear(1876)
                  .stream()
                  .anyMatch(
                    book ->
                       book.getYear() == 1876));
}Проверяем
Ответ:
Proxy + кодогенерация
Spring "предполагает" выборку по названию метода и параметрам.
List<Book> findByTitleAndYear(String title, int year);наименования полей сущности
Ключевые слова
Параметры метода
тип результата
| Keyword | Sample | JPQL snippet | 
|---|---|---|
| And | findByLastnameAndFirstname | 
 | 
| Or | findByLastnameOrFirstname | 
 | 
| Is,Equals | findByFirstname, findByFirstnameIs, findByFirstnameEquals | … where x.firstname = ?1 | 
Полный перечень см. здесь
PagingAndSortingRepository
public interface BookRepository
    extends CrudRepository<Book, Long>,
            PagingAndSortingRepository<Book, Long> {
}
         public Page<Book> findAtPage(int pageIndex,
                             int pageNumber,
                             Direction direction,
                             String sortField) {
  PageRequest request = PageRequest.of(
      pageIndex, pageNumber, direction, sortField);
  
  return bookRepository.findAll(request);
}public interface BookRepository
    extends CrudRepository<Book, Long>,
            JpaRepository<Book, Long> {
}
         public List<Book> findSame(Book book) {
   return bookRepository.findAll(Example.of(book));
}spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true select
        book0_.id as id1_0_,
        book0_.description as descript2_0_,
        book0_.title as title3_0_,
        book0_.year as year4_0_ 
    from
        book book0_ 
    where
        book0_.year=1876Specification API
public interface BookRepository
    extends CrudRepository<Book, Long>,
            JpaSpecificationExecutor<Book> {
}
         public class BookSpecifications {
    public static Specification<Book> byYearRange(int startYear, int finishYear) {
        return yearLessThan(finishYear).and(yearGreaterThan(startYear));
    }
    public static Specification<Book> yearLessThan(int finishYear) {
        return (root, query, criteriaBuilder) ->
            criteriaBuilder.lessThanOrEqualTo(root.get("year"), finishYear);
    }
    public static Specification<Book> yearGreaterThan(int startYear) {
        return (root, query, criteriaBuilder) ->
            criteriaBuilder.greaterThanOrEqualTo(root.get("year"), startYear);
    }
}public List<Book> FindInRange(Book book) {
   return bookRepository.findAll(
       BookSpecifications.byYearRange(1800, 1900));
}@Query - jpql
    @Query("select aob.book from "
        + "AuthorOfBook aob "
        + "join aob.author "
        + "where aob.author.lastname = ?1")
    List<Book> findByAuthor(String lastname);
Про jpql см. здесь
Hibernate: 
    select
        book1_.id as id1_2_,
        book1_.description as descript2_2_,
        book1_.title as title3_2_,
        book1_.year as year4_2_ 
    from
        author_of_book authorofbo0_ 
    inner join
        book book1_ 
            on authorofbo0_.book_id=book1_.id 
    inner join
        author author2_ 
            on authorofbo0_.author_id=author2_.id 
    where
        authorofbo0_.author_id=?Пишем свою имплементацию
(имя репозитория + Impl)
public interface BookComplexQueryRepository {
    List<Book> complexQueryMethod();
}@Repository
public class BookComplexQueryRepositoryImpl
            implements BookComplexQueryRepository {
    @Override
    public List<Book> complexQueryMethod() {
    ...public interface BookRepository
    extends CrudRepository<Book, Long>,
    PagingAndSortingRepository<Book, Long>,
    JpaRepository<Book, Long>,
    BookComplexQueryRepository { @Test
 public void testComplexQuery() {
    Assert.assertEquals(2, 
       bookRepository.complexQueryMethod().size());
 }