spring data jpa關聯查詢(一對一、一對多、多對多)
阿新 • • 發佈:2018-08-17
sse eager save net array ota println ack generate
在實際過往的項目中,常用的查詢操作有:1、單表查詢,2、一對一查詢(主表和詳情表)3、一對多查詢(一張主表,多張子表)4、多對多查詢(如權限控制,用戶、角色多對多)。做個總結,所以廢話不多說。
使用idea構建springboot項目,引入依賴如下:
dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
使用h2數據庫做測試用,application.yml配置如下:
spring: jpa: generate-ddl: true hibernate: ddl-auto: update properties: hibenate: format_sql: false show-sql: true
首先,一對一有好幾種,這裏舉例的是常用的一對一雙向外鍵關聯(改造成單向很簡單,在對應的實體類去掉要關聯其它實體的屬性即可),並且配置了級聯刪除和添加,相關類如下:
package io.powerx; importlombok.*; import javax.persistence.*; /** * Created by Administrator on 2018/8/15. */ @Getter @Setter @Entity public class Book { @Id @GeneratedValue private Integer id; private String name; @OneToOne(cascade = {CascadeType.PERSIST,CascadeType.REMOVE}) @JoinColumn(name="detailId",referencedColumnName = "id") private BookDetail bookDetail; public Book(){ super(); } public Book(String name){ super(); this.name =name; } public Book(String name, BookDetail bookDetail) { super(); this.name = name; this.bookDetail = bookDetail; } @Override public String toString() { if (null == bookDetail) { return String.format("Book [id=%s, name=%s, number of pages=%s]", id, name, "<EMPTY>"); } return String.format("Book [id=%s, name=%s, number of pages=%s]", id, name, bookDetail.getNumberOfPages()); } }
package io.powerx; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Getter @Setter @Entity(name = "BOOK_DETAIL") public class BookDetail { @Id @GeneratedValue private Integer id; @Column(name = "NUMBER_OF_PAGES") private Integer numberOfPages; @OneToOne(mappedBy = "bookDetail") private Book book; public BookDetail() { super(); } public BookDetail(Integer numberOfPages) { super(); this.numberOfPages = numberOfPages; } @Override public String toString() { if (null == book) { return String.format("Book [id=%s, name=%s, number of pages=%s]", id, "<EMPTY>"); } return String.format("Book [id=%s, name=%s, number of pages=%s]", id,book.getId(),book.getName()); } }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; /** * Created by Administrator on 2018/8/15. */ public interface BookRepository extends JpaRepository<Book,Integer> { Book findByName(String name); }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; /** * Created by Administrator on 2018/8/15. */ public interface BookDetailRepository extends JpaRepository<BookDetail, Integer>{ BookDetail findByNumberOfPages(Integer numberOfPages); }
package io.powerx; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import static org.junit.Assert.assertThat; @RunWith(SpringRunner.class) @SpringBootTest public class OnetooneApplicationTests { @Autowired private BookRepository bookRepository; @Autowired private BookDetailRepository bookDetailRepository; @Before public void init() { Book bookA = new Book("Spring in Action", new BookDetail(208)); Book bookB = new Book("Spring Data in Action", new BookDetail(235)); Book bookC = new Book("Spring Boot in Action"); bookRepository.saveAll(Arrays.asList(bookA, bookB, bookC)); } @After public void clear() { bookRepository.deleteAll(); } @Test public void find() { Book book = bookRepository.findByName("Spring in Action"); System.err.println(book.toString()); } @Test public void save() { Book book = new Book("springboot"); BookDetail bookDetail = new BookDetail(124); book.setBookDetail(bookDetail); bookRepository.save(book); } @Test public void delete() { bookRepository.deleteById(31); } @Test public void findbook(){ BookDetail bd = bookDetailRepository.findByNumberOfPages(235); System.err.println(bd.toString()); } }
一對多雙向,相關類如下:
package io.powerx; import lombok.Data; import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Getter @Setter @Entity public class Book { @Id @GeneratedValue private Integer id; private String name; @ManyToOne @JoinColumn(name="publishId") private Publisher publisher; @Override public String toString() { return "Book{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", publisher=" + publisher.getName() + ‘}‘; } public Book(String name) { this.name = name; } public Book() { } }
package io.powerx; import lombok.Data; import lombok.Getter; import lombok.Setter; import javax.persistence.*; import java.util.HashSet; import java.util.Set; /** * Created by Administrator on 2018/8/16. */ @Getter @Setter @Entity public class Publisher { @Id @GeneratedValue private Integer id; private String name; @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER) @JoinColumn(name="publishId",referencedColumnName = "id") private Set<Book> books; public Publisher() { super(); } public Publisher(String name) { super(); this.name = name; } @Override public String toString() { return "Publisher{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", books=" + books.size() + ‘}‘; } }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; /** * Created by Administrator on 2018/8/16. */ public interface BookRepository extends JpaRepository<Book,Integer>{ Book findByName(String name); }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; /** * Created by Administrator on 2018/8/16. */ public interface PublisherRepository extends JpaRepository<Publisher,Integer> { Publisher findByName(String name); }
package io.powerx; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashSet; import java.util.Set; @RunWith(SpringRunner.class) @SpringBootTest public class OnetomanyApplicationTests { @Autowired private PublisherRepository publisherRepository; @Autowired private BookRepository bookRepository; @Before public void init() { Book book1 = new Book("spring"); Book book2 = new Book("mvc"); Book book3 = new Book("mybatis"); Publisher publisher = new Publisher("zhonghua"); Set<Book> set = new HashSet<Book>(); set.add(book1); set.add(book2); set.add(book3); publisher.setBooks(set); publisherRepository.save(publisher); } @After public void clear() { publisherRepository.deleteAll(); } @Test public void find() { Publisher publisher = publisherRepository.findByName("zhonghua"); System.out.println(publisher); } @Test public void find2() { Book book = bookRepository.findByName("mvc"); System.out.println(book); } }
多對多雙向,相關代碼如下:
package io.powerx; import lombok.Getter; import lombok.Setter; import lombok.ToString; import javax.persistence.*; import java.util.Set; @Getter @Setter @Entity public class Author { @Id @GeneratedValue private Integer id; private String name; @ManyToMany(mappedBy = "authors",fetch = FetchType.EAGER) private Set<Book> books; public Author() { super(); } public Author(String name) { super(); this.name = name; } @Override public String toString() { return "Author{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", books=" + books.size() + ‘}‘; } }
package io.powerx; import lombok.Getter; import lombok.Setter; import lombok.ToString; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Getter @Setter @Entity public class Book { @Id @GeneratedValue private Integer id; private String name; @ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER) @JoinTable(name = "BOOK_AUTHOR", joinColumns = { @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")}, inverseJoinColumns = { @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID")}) private Set<Author> authors; public Book() { super(); } public Book(String name) { super(); this.name = name; this.authors = new HashSet<>(); } public Book(String name, Set<Author> authors) { super(); this.name = name; this.authors = authors; } @Override public String toString() { return "Book{" + "id=" + id + ", name=‘" + name + ‘\‘‘ + ", authors=" + authors.size() + ‘}‘; } }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface AuthorRepository extends JpaRepository<Author, Integer> { Author findByName(String name); List<Author> findByNameContaining(String name); }
package io.powerx; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface BookRepository extends JpaRepository<Book, Integer> { Book findByName(String name); List<Book> findByNameContaining(String name); }
在調試過程中,註意實體類的tostring方法的重寫,避免相互引用;此外如果超過兩張表的關聯查詢,建議使用自定義sql,建立相應的pojo來接收查詢結果。
spring data jpa關聯查詢(一對一、一對多、多對多)