18

I'm trying to fetch Entity1 by querying on mapped entities to it. I'm using CriteriaBuilder to perform this as shown below

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);

But In random cases, I found that the query was executed on "Entity2.entities1" without specifying Entity2 in join. My guess is that Entity2 is already available in session and it was lazily initialized with entities1. Because of this Criteria generates a query for Entity2 instead of Entity1.

Is there any way to restrict criteria to query on Entity1? or how to remove the Entity2 from session before executing this particular criteria.

Expected query,

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

But the query was generated as,

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

Entities structure:

public class Entity1 {

    @ManyToOne
    MappedEntity1 mappedEntity1;

    @OneToMany
    MappedEntity2 mappedEntity2;

    @OneToMany
    MappedEntity3 mappedEntity3;

}

and

public class Entity2 {

    @OneToMany
    List<Entity1> entities1;

    @OneToOne
    MappedEntity2 mappedEntity2;

}

Reference table for Entity1 and Entity2

Table name: 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)
Sled
  • 18,541
  • 27
  • 119
  • 168
dwayneJohn
  • 919
  • 1
  • 12
  • 30
  • 2
    The posted Criteria will (should) always query with a candidate of `Entity1`. That's all there is to say. If your JPA provider is querying something else then that is a bug in your JPA provider. The L1 cache contents is nothing to do with it. –  Oct 30 '18 at 11:21
  • Are you sure the query you posted is the only one issued? The query might be a part of eagerly fetching one of the associated entities *after* the query you expected has been executed, but it's hard to tell, since the entities you posted are incomplete – crizzis Nov 02 '18 at 15:31
  • Which Hibernate version are you using? – Roshana Pitigala Nov 03 '18 at 13:57

6 Answers6

1

I don't think it's random. I'm pretty sure there's something wrong in your mapping.

I can see some thing that don't seem right in your question and you are not showing some information.

The mapping on Entity1 seems wrong, I'm assuming what you mean is:

public class Entity1 {

    @ManyToOne
    MappedEntity1 mappedEntity1;

    @ManyToOne // instead of @OneToMany
    MappedEntity2 mappedEntity2;

    @ManyToOne // instead of @OneToMany
    MappedEntity3 mappedEntity3;

}

And you are not showing the mapping of MappedEntity2, only the mapping of Entity2. So I don't know if the bidirectional association is correct.

Even after all this, I think the problem is that you didn't add the mappedBy attribute to the one-to-many association.

Hibernate is querying entities1_entities2 because you've defined a unidirectional one-to-many in Entity2 and this mapping assumes there is a table called entities1_entities2 mapping the association.

If the association is bidirectional, you need a field in Entity1 like this:

class Entity1 {

   @ManyToOne
   Entity2 entity2;

   ...

}

Then you can add the mappedBy attribute to entities1 in Entity2:

public class Entity2 {

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

    ...
}

This will generate the correct query when you join the two entities. Anyway, if you want a better answer you need to improve the question.

Davide D'Alto
  • 7,421
  • 2
  • 16
  • 30
0

First, you need to check whether the old entity exist or not before you go querying new entity. You can directly try pass your the entity to session.delete(), in order to delete that object. There should be an exception if no record found in the database which need to be handled. In fact, we usually don't really get this case. We always delete an existing entity, I mean usual logic is like that; so, no need to do that if already done. You can simply do this,

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

or you can do this instead,

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

By the way, you can also use this version session.delete(String query),

session.delete("from Entity1 e where e.id = '1234'"); // Just found it is deprecated
Varun Jain
  • 1,371
  • 12
  • 26
0

I'm not 100% sure about this. Try closing the current session and opening another one before executing your search.

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

This should clear the previously created (lazy initialized) entities.

Roshana Pitigala
  • 8,437
  • 8
  • 49
  • 80
0

Try loading the instance you want to remove and delete it.

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));
0

If you want to remove any entity from Hibernate session, you can do that in 2 steps : 1-Making sure that Hibernate persisted all pending changes in the database 2-Removing the entities from the persistence context

em.flush(); //Write all pending changes to the DB
em.detach(Entity2);// Remove Entity2 from the persistence context
-3

Most IDEs can handle entities for you. You might be able to find a tool that displays all entities and lets you modify them in your IDE of choice.

Grizzly
  • 179
  • 1
  • 2
  • 12