如何从Hibernate会话中删除不需要的实体?

时间:2018-10-30 04:53:45

标签: java spring hibernate jpa lazy-initialization

我正在尝试通过查询映射到的实体来获取Entity1。我正在使用CriteriaBuilder来执行此操作,如下所示

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Entity1> createQuery = criteriaBuilder.createQuery(Entity1.class);
Root<Entity1> root = createQuery.from(Entity1.class);
Join<Entity1, MappedEntity2> mappedEntity2Join = root.join("mappedEntity2");
createQuery.select(root);

predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get(COL_USER_ID), userId));

// where clause to filter by query params
createQuery.where(predicate).distinct(true);
createQuery.getRestriction();

TypedQuery<Entity1> query = entityManager.createQuery(createQuery);

但是在随机情况下,我发现查询是在“ Entity2.entities1”上执行的,而未在联接中指定Entity2。我的猜测是,Entity2在会话中已经可用,并且已使用entity1进行了延迟初始化。因此,该条件为Entity2而不是Entity1生成了查询。

有什么方法可以限制条件以对Entity1进行查询?或如何在执行此特定条件之前从会话中删除Entity2。

预期查询

select * 
from Entity1 obj1_ 
inner join mappedEntity1 mObj_ on obj1_.obj_id=mObj_.id 
where obj1_.id=?

但是查询生成为

select * 
from entities1_entities2 obj0_ 
inner join Entity1 obj1_ on obj0_.obj_id=obj1_.id 
where obj0_.entity2_id=?

实体结构:

public class Entity1 {

    @ManyToOne
    MappedEntity1 mappedEntity1;

    @OneToMany
    MappedEntity2 mappedEntity2;

    @OneToMany
    MappedEntity3 mappedEntity3;

}

public class Entity2 {

    @OneToMany
    List<Entity1> entities1;

    @OneToOne
    MappedEntity2 mappedEntity2;

}

Entity1和Entity2的引用表

表名: entities1_entities2

entity1_id INTEGER NOT NULL,
entity2_id INTEGER NOT NULL,
CONSTRAINT entities1_entities2_entity1_id_fkey FOREIGN KEY (entity1_id)
REFERENCES entity1 (id),
CONSTRAINT entities1_entities2_entity2_id_fkey FOREIGN KEY (entity2_id)
    REFERENCES entity2 (id)

4 个答案:

答案 0 :(得分:0)

首先,您需要在查询新实体之前检查旧实体是否存在。您可以直接尝试将实体传递给session.delete(),以删除该对象。如果在数据库中找不到需要处理的记录,应该有一个例外。实际上,我们通常不会真正遇到这种情况。我们总是删除一个现有的实体,我的意思是通常的逻辑就是这样。因此,如果已经完成,则无需这样做。您可以简单地做到这一点,

Entity1 ent = session.load(Entity1.class, '1234');
session.delete(ent);

或者您也可以这样做

Entity1 ent = new Entity1('1234'); // used constructor for brevity
session.delete(ent);

顺便说一句,您也可以使用此版本session.delete(String query),

session.delete("from Entity1 e where e.id = '1234'"); // Just found it is deprecated

答案 1 :(得分:0)

对此我不是100%肯定。在执行搜索之前,请尝试关闭当前会话并打开另一个会话。

session.close();
session = sessionFactory.openSession();

这应该清除先前创建的(延迟初始化的)实体。

答案 2 :(得分:0)

大多数IDE都可以为您处理实体。您也许可以找到一个显示所有实体并允许您在选择的IDE中对其进行修改的工具。

答案 3 :(得分:0)

尝试加载您要移除的实例并将其删除。

private boolean deleteById(Class<?> type, Serializable id) {
        Object persistentInstance = session.load(type, id);
        if (persistentInstance != null) {
            session.delete(persistentInstance);
            return true;
        }
        return false;
    }


boolean result = deleteById(Product.class, new Long(41));