commit 3298d11bd8f89cf1e523dbc7965b6dcaad987bc5 Author: lanyuanxiaoyao Date: Tue Dec 3 23:23:38 2024 +0800 实践JPA查询 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ca206d5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b562cfb --- /dev/null +++ b/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + org.example + jpa-library + 1.0-SNAPSHOT + + + 11 + 11 + UTF-8 + + 2.6.15 + 2021.0.9 + 5.1.0 + + + + + org.projectlombok + lombok + 1.18.34 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.blinkfox + fenix-spring-boot-starter + 2.7.0 + + + com.querydsl + querydsl-jpa + ${querydsl.version} + + + com.querydsl + querydsl-apt + ${querydsl.version} + provided + + + com.h2database + h2 + runtime + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + + process + + + target/generated-sources/java + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/lanyuanxiaoyao/jpa/Application.java b/src/main/java/com/lanyuanxiaoyao/jpa/Application.java new file mode 100644 index 0000000..5a4bd7a --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/jpa/Application.java @@ -0,0 +1,74 @@ +package com.lanyuanxiaoyao.jpa; + +import com.blinkfox.fenix.EnableFenix; +import com.lanyuanxiaoyao.jpa.entity.Company; +import com.lanyuanxiaoyao.jpa.entity.User; +import com.lanyuanxiaoyao.jpa.repository.CompanyRepository; +import com.lanyuanxiaoyao.jpa.repository.UserRepository; +import java.time.LocalDateTime; +import javax.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Slf4j +@EnableFenix +@EnableJpaAuditing +@SpringBootApplication +public class Application implements ApplicationRunner { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Resource + private UserRepository userRepository; + @Resource + private CompanyRepository companyRepository; + + @Override + public void run(ApplicationArguments args) throws Exception { + Company company1 = createCompany("Company 1"); + log.info("Company 1: {}", company1); + + User user1 = createUser("User 1", LocalDateTime.now(), User.Type.STUDENT, company1); + log.info("User 1: {}", user1); + User user2 = createUser("User 2", LocalDateTime.now(), User.Type.TEACHER, company1); + log.info("User 2: {}", user2); + + // companyRepository.delete(company1); + + /*Iterable user = userRepository.findAll(((root, query, builder) -> { + return builder.and( + builder.equal(root.get("name"), "User 1") + // builder.equal(root.get("type"), "STUDENT"), + // builder.isNotNull(root.get("company").get("name")) + ); + }));*/ + /*Iterable user = userRepository.findAll(builder -> builder + .andEquals("type", "STUDENT") + .build());*/ + // log.info("User: {}", user.iterator().next().getCompany()); + + companyRepository.findAll(((root, query, builder) -> { + return builder.isEmpty(root.get("users")); + })); + } + + private Company createCompany(String name) { + Company company = new Company(); + company.setName(name); + return companyRepository.saveAndFlush(company); + } + + private User createUser(String name, LocalDateTime birthday, User.Type type, Company company) { + User user = new User(); + user.setName(name); + user.setBirthday(birthday); + user.setType(type); + user.setCompany(company); + return userRepository.saveAndFlush(user); + } +} diff --git a/src/main/java/com/lanyuanxiaoyao/jpa/entity/Company.java b/src/main/java/com/lanyuanxiaoyao/jpa/entity/Company.java new file mode 100644 index 0000000..6520a52 --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/jpa/entity/Company.java @@ -0,0 +1,52 @@ +package com.lanyuanxiaoyao.jpa.entity; + +import java.time.LocalDateTime; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@Setter +@ToString +@Entity +@EntityListeners(AuditingEntityListener.class) +@Table(name = "jpa_company") +@NamedEntityGraph(name = "company.list", attributeNodes = { + @NamedAttributeNode("users") +}) +@SQLDelete(sql = "update jpa_company set deleted = true where id = ?") +@Where(clause = "deleted = false") +public class Company { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + @OneToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, mappedBy = "company") + @ToString.Exclude + @Where(clause = "deleted = false") + private List users; + @Column(nullable = false) + private Boolean deleted = false; + @CreatedDate + private LocalDateTime createdTime; + @LastModifiedDate + private LocalDateTime modifiedTime; +} diff --git a/src/main/java/com/lanyuanxiaoyao/jpa/entity/User.java b/src/main/java/com/lanyuanxiaoyao/jpa/entity/User.java new file mode 100644 index 0000000..ae00eb6 --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/jpa/entity/User.java @@ -0,0 +1,67 @@ +package com.lanyuanxiaoyao.jpa.entity; + +import java.time.LocalDateTime; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.Table; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@Setter +@ToString +@Entity +@EntityListeners(AuditingEntityListener.class) +@Table(name = "jpa_user") +@NamedEntityGraph(name = "user.list", attributeNodes = { + @NamedAttributeNode("company") +}) +@SQLDelete(sql = "update jpa_user set deleted = true where id = ?") +@Where(clause = "deleted = false") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(nullable = false) + private String name; + private LocalDateTime birthday; + @ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY) + @JoinColumn(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + @ToString.Exclude + @Where(clause = "deleted = false") + private Company company; + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private Type type; + @Column(nullable = false) + private Boolean deleted = false; + @CreatedDate + private LocalDateTime createdTime; + @LastModifiedDate + private LocalDateTime modifiedTime; + + public enum Type { + STUDENT, + TEACHER, + } +} diff --git a/src/main/java/com/lanyuanxiaoyao/jpa/repository/CompanyRepository.java b/src/main/java/com/lanyuanxiaoyao/jpa/repository/CompanyRepository.java new file mode 100644 index 0000000..4abf92e --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/jpa/repository/CompanyRepository.java @@ -0,0 +1,12 @@ +package com.lanyuanxiaoyao.jpa.repository; + +import com.blinkfox.fenix.jpa.FenixJpaRepository; +import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor; +import com.lanyuanxiaoyao.jpa.entity.Company; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.repository.query.QueryByExampleExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface CompanyRepository extends FenixJpaRepository, FenixJpaSpecificationExecutor, QueryByExampleExecutor, QuerydslPredicateExecutor { +} diff --git a/src/main/java/com/lanyuanxiaoyao/jpa/repository/UserRepository.java b/src/main/java/com/lanyuanxiaoyao/jpa/repository/UserRepository.java new file mode 100644 index 0000000..166e55f --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/jpa/repository/UserRepository.java @@ -0,0 +1,18 @@ +package com.lanyuanxiaoyao.jpa.repository; + +import com.blinkfox.fenix.jpa.FenixJpaRepository; +import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor; +import com.lanyuanxiaoyao.jpa.entity.User; +import java.util.List; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.repository.query.QueryByExampleExecutor; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends FenixJpaRepository, FenixJpaSpecificationExecutor, QueryByExampleExecutor, QuerydslPredicateExecutor { + @EntityGraph("user.list") + @Override + List findAll(Specification spec); +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..73f3593 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,12 @@ +spring: + datasource: + url: jdbc:h2:mem:test;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE + username: lanyuanxiaoyao + password: lanyuanxiaoyao + driver-class-name: org.h2.Driver + jpa: + generate-ddl: true + show-sql: true +fenix: + print-banner: false + print-sql: false \ No newline at end of file