本文介绍了如何用谓词过滤子实体集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个实体服务,需要根据ID列表对子实体的集合进行过滤.我的服务有一个公共方法,可以接收父实体的ID和他的某些子实体的ID列表.

I have an entity service on which I need to filter a collection of child entity, based on a list of id's. My service have a public method which receive the id of the parent entity and a list of id's of some of his children entities.

默认情况下,我知道JPA将获取所有相关实体,这是他的实际行为.但是我们需要致力于服务的性能.因此,我不想只获取所有相关实体并使用许多循环(对ID以及对其他属性(如date属性)进行过滤)对其进行过滤,而是希望仅获得与我的请求有关的实体.

By default, I know that JPA will fetch all related entities and this his the actual behavior. But we need to work on the performance of the service. So instead of getting all related entities and filter them with many loop (filter on id's and also on other properties like date property), I want to get only entities concerned by my request.

我的父母实体

@Entity
@Table(name = "MyParent")
public class MyParentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
        generator = "SEQ_MyParent")
    @SequenceGenerator(allocationSize = 1, name = "SEQ_MyParent",
        sequenceName = "SEQ_MyParent")
    @Column(name = "ID_PARENT")
    private Long id;

    @OneToMany(mappedBy = "myParent", cascade = CascadeType.ALL,
        fetch = FetchType.EAGER, orphanRemoval = true)
    private final List<MyChildEntity> myChild = new ArrayList<MyChildEntity>();

}

我的孩子实体

@Entity
@Table(name = "MyChild")
public class MyChildEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
        generator = "SEQ_MyChild")
    @SequenceGenerator(allocationSize = 1, name = "SEQ_MyChild",
        sequenceName = "SEQ_MyChild")
    @Column(name = "ID_CHILD")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "ID_PARENT")
    private MyParentEntity myParent;
}

我正在使用Spring-data CrudRepository从数据库中获取数据,并且我还扩展了JpaSpecificationExecutor以使用谓词.

I'm using Spring-data CrudRepository to get data from my DB and I also extends JpaSpecificationExecutor to use Predicate.

public interface MyParentRepository extends CrudRepository<MyParentEntity, Long>,
    JpaSpecificationExecutor<MyParentEntity> {
}

这让我使用CrudRepository findOne()方法,但使用Specification对象而不是常规Long参数.

This let me use CrudRepository findOne() method but with a Specification object instead of the regular Long parameter.

此外,我将倍数规范的对象与以下调用结合在一起:

Also, I combine multiples Specification's object with the following call:

this.myParentRepository.findOne(Specifications
    .where(firstSpecification(parentId))
    .and(secondSpecification(childrenIdsList)));

我创建了一个简单的junit测试,其中一个Parent链接到两个子实体.在我的请求中,我可以使用提供的ID来获取父实体.但是,即使我提供了孩子ID,也总是在父级列表中同时获得两个孩子实体.

I created a simple junit test with one Parent linked to two children entities. In my request, I'm able to get the parent entity with the provided Id. But even if I provide the child id, I always get both children entities in the list inside the parent.

在我的方法中,该方法返回一个新的Specification对象,在其中重写了toPredicate方法,我无法创建一个谓词,该谓词将过滤我的子对象集合并仅获取我感兴趣的那些对象.我知道休眠标准可以添加限制",但这在toPredicate方法附带的CriteriaBuilder中不可用.

In my method which return a new Specification object, in which the toPredicate method is override, I'm unable to create a Predicate that will filter my children collection and only get those one I'm interested. I know that the Hibernate Criteria has the possibility to add "Restrictions" but this is not available in the CriteriaBuilder that is provided with the toPredicate method.

public static Specification<MyParentEntite> firstSpecification(final Long id) {
    return new Specification<MyParentEntite>() {

        @Override
        public Predicate toPredicate(Root<MyParentEntite> root,
            CriteriaQuery<?> query, CriteriaBuilder cb) {

            Predicate predicate = cb.equal(root.get(MyParentEntity_.id), id);
            return cb.and(predicate);
        }
    };
}

public static Specification<MyParentEntite> secondSpecification(final List<Long> ids) {
    return new Specification<MyParentEntite>() {

        @Override
        public Predicate toPredicate(Root<MyParentEntite> root,
            CriteriaQuery<?> query, CriteriaBuilder cb) {

            Root<MyChildEntity> child = query.from(MyChildEntity.class);
            Expression<Long> exp = child.get(MyChildEntity_.id);
            Predicate p = exp.in(ids);
            return cb.and(p);
        }
    };
}

在secondSpecification()方法中,我还尝试在实体中直接使用ListJoin而不是Root.我在这里搜索了其他问题,但是似乎可以通过Hibernate Criteria限制或LeftJoin解决此问题,这是我在ListJoin中指定JoinType.LEFT参数时尝试的.

In the secondSpecification() method, I also tried to use ListJoin instead of Root directly in the Entity. I searched in other questions here but it seems that this concern is solved with the Hibernate Criteria restrictions or with a LeftJoin, which I tried in my ListJoin in specifing JoinType.LEFT parameter.

以下是已成功测试的解决方案的链接:

Here are links to already tested solutions whitout success :

JPA CriteriaBuilder-如何使用"IN"比较运算符

JPA2标准API:在...中选择...(从

我想提一下,我对Criteria API和Predicate还是比较陌生.也许我缺少一些简单的东西,但是对于经验丰富的JPA开发人员来说,这是显而易见的!

I want to mention that I'm relatively new with Criteria API and Predicate. Maybe I'm missing something that is simple but that is obvious to experienced JPA developpers!

非常感谢您的帮助!

推荐答案

最后,我找到了解决问题的方法.从数据完整性的角度来看,仅请求部分子实体集合是很危险的.如果远程服务通过get内的部分子实体集合来请求我的父实体,则该父实体对象可能会返回以进行修改操作,这将导致对子实体的已删除实例进行许多删除"调用.持久性API会将这些丢失的子级视为已删除的关系,这是我们不希望的.

Finally, I found a way to resolved my issue. Requesting only partial collections of sub-entities is something that we found dangerous in terms of data integrity. If a remote service calls to request my parent entity with a partial collection of children's entities within a get, this parent entity object may be return for a modify operation which will result in many "delete" calls on the removed instances of children entities. The persistence API will consider these missing children as relations that were removed, which is something we don't want.

我创建了一个伪传输对象,该对象包含所请求的子实体的部分集合,因此该伪传输对象不能在以后的修改操作调用中使用.父实体的完整版本将用于修改"目的.

I created a dummy transfert object which contains the partial collections of children's entities requested so this dummy transfert object can't not be use in a future modify operation call. The full version of the parent entity will be used for the "modify" purpose.

这篇关于如何用谓词过滤子实体集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 01:50