【问题标题】:JPA with Specification - How to filter an entity by a child collection content?JPA with Specification - 如何按子集合内容过滤实体?
【发布时间】:2017-03-17 12:45:05
【问题描述】:

我遇到了一个问题,即通过列表中子项的值过滤实体。 例如:

public class Father(){
  private String name;
  private Set<Child> childs;
}
public class Child(){
  private String name;
  private Integer age;
  private School school;
}
public class School(){
  private String name;
}

我想过滤所有在 X 学校有孩子的父亲。

这是我所做的,但无法正常工作:

 Specification specs = new Specificatrion(){
        @Override
        public Predicate toPredicate(Root<Father> root, CriteriaQuery<?> query, final CriteriaBuilder cb){
             Root<Child> childRoot = query.from(Child.class);
             Path<?> path = childRoot.get(Child_.school.name);
             Predicate pred = exp.in("School Name");
             return cb.and(pred);
         }
}

有人可以帮我解决这个问题吗? 谢谢!

【问题讨论】:

    标签: java jpa filter specifications


    【解决方案1】:

    您必须在孩子与父亲之间建立反向关系,这样孩子才能在学校和父亲之间架起桥梁。

    这样的事情会起作用:

    @Entity
    public class Father {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String name;
    
        @OneToMany(mappedBy = "father", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        private Set<Child> childs = new HashSet<>();
    
    
    @Entity
    public class Child {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
        private String name;
        private Integer age;
    
        @ManyToOne(cascade=CascadeType.ALL)
        private Father father;
    
        @OneToOne(cascade = CascadeType.PERSIST)
        private School school;
    

    然后在您的父亲存储库中:

    @Query("select father from Child child join child.father father join child.school school where school.name=:school")
    List<Father> findBySchool(@Param("school") String school);
    

    【讨论】:

    • 嗨,Essex,我想使用规范。会尝试改变,看看会发生什么,谢谢!
    • 您可以使用规范,但我认为您不能拥有您在问题中设置的层次结构。很高兴被证明是错误的。
    【解决方案2】:

    我知道已经晚了。但可能会对某人有所帮助。

    我的实体 InwardInventory 具有子实体 InwardOutwardList 的列表,再次具有子产品的列表。因此,要过滤具有特定产品的 InwardInventories。

    Specification<InwardInventory> finalSpec = null;
    
    finalSpec = specbldr.whereChildFieldListContains(
                    InwardInventory_.INWARD_OUTWARD_LIST,InwardOutwardList_.PRODUCT,Product_.PRODUCT_NAME,productNames));
    

    specbldr.whereChildFieldListContains 方法的通用定义

    public Specification<T> whereChildFieldListContains(String childTableName, String gcTable,String fieldName, List<String> names) 
        {
            Specification<T> finalSpec = null;
            for(String name:names)
            {
                Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
                    -> cb.like(root.join(childTableName).join(gcTable).get(fieldName), "%"+name+"%" );
                    finalSpec  = specOrCondition(finalSpec,internalSpec);
            }
            return finalSpec;
        }
    

    如果您需要进一步的帮助,请告诉我

    【讨论】:

      猜你喜欢
      • 2013-03-23
      • 1970-01-01
      • 2022-12-16
      • 2016-12-27
      • 2014-10-26
      • 2018-07-04
      • 1970-01-01
      • 2017-12-13
      • 2019-07-10
      相关资源
      最近更新 更多