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

我试图通过查询映射到它的实体来获取。我正在使用如下图来执行此操作Entity1CriteriaBuilder

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。我的猜测是,实体 2 已经在会话中可用,并且它被懒惰地初始化为实体 1。因此,条件会生成对实体 2 而不是实体 1 的查询。

有没有办法限制在实体 1 上查询的条件?或者如何在执行此特定条件之前从会话中删除 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;

}

实体 1 和实体 2 的参考表

表名: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)

答案 1

我不认为这是随机的。我很确定您的映射中有问题。

我可以看到一些在你的问题中似乎不对劲的事情,你没有显示一些信息。

Entity1上的映射似乎是错误的,我假设你的意思是:

public class Entity1 {

    @ManyToOne
    MappedEntity1 mappedEntity1;

    @ManyToOne // instead of @OneToMany
    MappedEntity2 mappedEntity2;

    @ManyToOne // instead of @OneToMany
    MappedEntity3 mappedEntity3;

}

并且您没有显示 的映射,只显示了 的映射。所以我不知道双向关联是否正确。MappedEntity2Entity2

即使经过所有这些,我认为问题在于您没有将属性添加到一对多关联中。mappedBy

Hibernate 正在查询,因为您已在 Entity2 中定义了单向一对多,并且此映射假定存在一个名为映射关联的表。entities1_entities2entities1_entities2

如果关联是双向的,则需要如下字段:Entity1

class Entity1 {

   @ManyToOne
   Entity2 entity2;

   ...

}

然后,您可以将该属性添加到 Entity2 中:mappedByentities1

public class Entity2 {

    @OneToMany(mappedBy="entity2") 
    List<Entity1> entities1;

    ...
}

这将在联接两个实体时生成正确的查询。无论如何,如果你想要一个更好的答案,你需要改进这个问题。


答案 2

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

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

或者你可以这样做,

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

顺便说一句,您也可以使用此版本的会话.delete(字符串查询),

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

推荐