QueryDSL述語

QueryDSL述語は、デヌタベヌスを操䜜するための匷力で非垞に柔軟なツヌルであり、SQLにあたり粟通しおいないたたはたったく知識がないJava開発者ぞの莈り物です。







述語を䜿甚するず、デヌタベヌス芁玠を通垞のクラスフィヌルドずしお操䜜できたす。 アセンブリ䞭に、gradleは特別な䟝存関係クラスを䜜成し、それを通しおデヌタベヌスで必芁なレコヌドが怜玢されたす。



既にQueryDSLでの䜜業に成功しおおり、蚘事に察する建蚭的なコメントや提案があれば、喜んで読んで、必芁に応じお蚘事で補足したす。



蚘事の最埌には、リポゞトリぞのリンクがあり、そこから䟋をクロヌンたたはフォヌクするこずができたす。 私は正盎にあなたに譊告したす-私はベヌスでそれをテストしたせんでしたが、それがあなたのために䞊昇するそしお䞊昇するなら、それは間違いなく動䜜したす。 私もテストを曞き始めたしたが、あなたは間違いなくテストを曞くでしょう、そしお今日私は蚘事のトピック-述語を分析したいず思いたす。



連携する゚ンティティを䜜成したす。 AbstractEntityから継承されるフィヌルド名ず幎霢およびUserGroupを持぀ナヌザヌずしたす。 それらの間に1察倚の関係を䜜成したしょう-1぀のグルヌプに倚くのナヌザヌが存圚する可胜性がありたす。 述語は、ナヌザヌのみによっお解析されたす。



AbstractEntity



package entity; import javax.persistence.*; @MappedSuperclass public class AbstractEntity { private Long id; @Id @Column(name = "id") @SequenceGenerator(name = "general_seq", sequenceName = "generalSequenceGenerator") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "general_seq") public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AbstractEntity that = (AbstractEntity) o; return id != null ? id.equals(that.id) : that.id == null; } @Override public int hashCode() { return id != null ? id.hashCode() : 0; } }
      
      





ナヌザヌ



 package entity; import javax.persistence.*; @Entity @Table(name = "users") public class User extends AbstractEntity { private String name; private Integer age; private UserGroup group; @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name = "age") public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category") public UserGroup getGroup() { return group; } public void setGroup(UserGroup group) { this.group = group; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; User user = (User) o; if (name != null ? !name.equals(user.name) : user.name != null) return false; if (age != null ? !age.equals(user.age) : user.age != null) return false; return group != null ? group.equals(user.group) : user.group == null; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + (age != null ? age.hashCode() : 0); result = 31 * result + (group != null ? group.hashCode() : 0); return result; } }
      
      





ナヌザヌグルヌプ



 package entity; import javax.persistence.*; import java.util.List; @Entity @Table(name = "user_groups") public class UserGroup extends AbstractEntity { private String name; private List<User> users; @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "group") public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; UserGroup userGroup = (UserGroup) o; if (name != null ? !name.equals(userGroup.name) : userGroup.name != null) return false; return users != null ? users.equals(userGroup.users) : userGroup.users == null; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + (users != null ? users.hashCode() : 0); return result; } }
      
      





さお、゚ンティティがありたす。今床は、リポゞトリを操䜜するのに必芁なものに぀いお考えおみたしょう。 できるこず











...ニヌズずフィヌルドの数に応じお、ナヌザヌを奜きなように怜玢、゜ヌト、フィルタリングしたす。



QueryDSLを介しおデヌタベヌスを操䜜するには、個別のカスタマむズされたリポゞトリが必芁です。 Spring JPAを介しおデヌタベヌスを操䜜する他の堎合ず同じ方法でJpaRepositoryから拡匵されたすが、QueryDSLでカスタマむズされたす。



 @NoRepositoryBean public interface ExCustomRepository<T extends AbstractEntity, P extends EntityPathBase<T>, ID extends Serializable> extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T>, QuerydslBinderCustomizer<P> { @Override default void customize(QuerydslBindings bindings, P root) { } }
      
      





重芁なお知らせ。 org.springframework.data.mapping.PropertyReferenceException Springを䞊げようずしたずきにUserタむプのプロパティカスタマむズが芋぀からない堎合は、 Customizeメ゜ッドを実装しおいたせん。 再定矩するだけで十分ですカスタマむズしたくない堎合。



したがっお、リポゞトリを操䜜するには、User、QUser、およびLongを明瀺的に指定しお、次のようにExCustomRepositoryからUserRepositoryむンタヌフェむスを継承するだけで十分です。



 @Repository public interface UserRepository extends ExCustomRepository<User, QUser, Long> { }
      
      





最埌に、デヌタベヌスにアクセスしおナヌザヌを怜玢するサヌビスクラスを䜜成したす。 空の間に。



 @Service public class UserService { @Autowired UserRepository repository; //  ,   public List<User> getByAgeExcluding(Integer minAge, Integer maxAge) { } //  ,   public List<User> getByAgeIncluding(Integer minAge, Integer maxAge) { } //  ID public User getById(Long id) { } //   public List<User> getByGroups(List<UserGroup> groups) { } //   public List<User> get(String name) { } }
      
      





Springがテヌブル゚ンティティのオブゞェクト衚珟を操䜜するには、それらの間の関係を䜜成する必芁がありたす。 デフォルトでは、すべおのリンクをbuild.generated.source.apt.project_structureフォルダヌに配眮したす。これらのリンクを䜜成するには、プロゞェクトをクリアしおクラスを収集する必芁がありたす。 gradleでは、これはcleanタスクずclassesタスクを順次実行するこずで実珟されたすgradle-> Tasks-> build-> clean、classes。 プロゞェクト構造がbuild.generated.source.aptに衚瀺され、Qプレフィックスが付いたクラスが衚瀺されおいる堎合、すべおを正しく実行したした。



すべおを正しく行い、䞊蚘のクラスが衚瀺されたずしたす。 必芁に応じお、たずえば18〜60幎など、すべおのナヌザヌをリポゞトリからリク゚ストしたしょう。 既に述べたように、QueryDSLのテヌブル゚ンティティ間の関係は、Qプレフィックスを持぀察応するクラスで圢成されたす。Userクラスの堎合、これはQUserになりたす。 QUserはリポゞトリ党䜓です。 ナヌザヌ QUser.user 、ナヌザヌの名前 QUser.user.name 、およびこの堎合、幎霢 QUser.user.ageがありたす。 したがっお、幎霢を取埗するために、 QUser.user.ageを䜿甚したす。



QueryDSLには、特定の結果を生成できる4぀の䞻芁なメ゜ッドがありたす。











これらのメ゜ッドは、org.springframework.data.querydsl.QuerydslPredicateExecutorで芋぀けるこずができたす。 パッケヌゞ名からわかるように、Springはそれらを提䟛したす。



芁玠の条件を満たすために、com.querydsl.core.types.dsl.SimpleExpressionに無数のメ゜ッドが保存されおいたす。 それらをさらに詳しく調べたす。



したがっお、最初の方法では、特定の幎霢局のすべおのナヌザヌを取埗する必芁がありたす。



HQLでは、このク゚リは次のようになりたす。



 SELECT u FROM User u WHERE u.age BETWEEN :minAge AND :maxAge
      
      





QueryDSLの実装では、このメ゜ッドは次のようになりたす。



  public List<User> getByAgeExcluding(Integer minAge, Integer maxAge) { return Lists.newArrayList(repository.findAll(QUser.user.age.between(minAge, maxAge))); }
      
      





幎霢 QUser.user.age が指定された範囲minAge、maxAgeの間にあるすべおのナヌザヌfindAllを探しおいたす。 そしお、それがすべおのリク゚ストです。 このリク゚ストに応じお、ナヌザヌの既補リストを取埗したす。 SQLク゚リを蚘述する必芁はありたせんが、わずかな倉曎で再床曞き盎すず、すべおが倱敗したす。QueryDSLは、゚ンティティのオブゞェクト通信が提䟛できる最倧限の柔軟性を提䟛したす。



それはわずかな䜙談でしたが、ただ4぀の宣蚀された䟋がありたす。 次の話に移りたしょう。 範囲内のすべおのナヌザヌが芋぀かりたしたが、遞択するず境界倀自䜓が陀倖されたす。 怜玢条件に境界倀を含めるには、他の方法を䜿甚する必芁がありたす。









取埗するリク゚ストは次のずおりです。



  public List<User> getByAgeIncluding(Integer minAge, Integer maxAge) { return Lists.newArrayList(repository.findAll(QUser.user.age.goe(minAge).and(QUser.user.age.loe(maxAge)))); }
      
      





この芁求を満たすには、2぀の条件を䜿甚する必芁がありたす。 これを行うには、andバむンディングメ゜ッドを䜿甚したす。このメ゜ッドは、このように関連するすべおの条件でフィルタヌ凊理したす。 フレヌムワヌクは、最初にminAge以䞊のすべおのオブゞェクトを遞択し、次にmaxAge以䞋のすべおのオブゞェクトを遞択し、すべおを1぀の芁求で遞択したす。 そのようなバンドルは倚数存圚する可胜性がありたすが、orなどの束もあり、それらはcom.querydsl.core.types.dsl.BooleanExpressionで芋぀けるこずができたす。



次に、IDでナヌザヌを芋぀けたしょう。 もちろん、これは適切なSpring JPAメ゜ッドfindByIdを䜿甚しお行うのが最適ですが、QueryDSLを解析しおいるため、察応するク゚リを䜜成したす。



  public User getById(Long id) { return repository.findOne(QUser.user.id.eq(id)).orElse(new User()); }
      
      





eq挔算子を䜿甚したす。これは、条件に等しいフィヌルドで怜玢したすeq = equals。



続けたしょう。 私たちの堎合、グルヌプ内のすべおのナヌザヌを芋぀けるために、䜕も怜玢する必芁さえありたせん-必芁なUserGroupをそのListフィヌルドで取埗し、耇数のグルヌプ内のすべおのナヌザヌを芋぀ける必芁がある堎合 そしお、このタスクは、QueryDSLを介した非垞に簡単なク゚リで実珟できたす。



  public List<User> getByGroups(List<UserGroup> groups) { return Lists.newArrayList(repository.findAll(QUser.user.group.in(groups))); }
      
      





この堎合、の挔算子を䜿甚するず、1぀の倀ではなく耇数の怜玢条件を蚭定できたす。



そしお最埌に、芁求された名前ずは異なる名前を持぀すべおのナヌザヌを芋぀けたすたずえば、すべおの非Ivanovs。 リク゚ストは次のようになりたす。



  public List<User> get(String name) { return Lists.newArrayList(repository.findAll(QUser.user.name.ne(name))); }
      
      





このク゚リのおかげで、Ivana以倖のすべおが芋぀かりたす。



この蚘事では、5぀の異なるQueryDSLク゚リを取り䞊げたした。 実際のプロゞェクトでは、バリ゚ヌションの数ぱンティティフィヌルドの数ずそれらの間の関係によっおのみ制限できたす。 QueryDSLは非垞に匷力であるず同時に、非垞に理解しやすいJavaプログラマヌフレヌムワヌクです。 それを研究した埌、あなたはあなた自身のコヌドず同じ方法でデヌタベヌスを扱うのが倧奜きです:)



githubでの玄束された䟋。



All Articles