¿Por qué mi consulta JQL devuelve un resultado diferente al de la consulta CriteriaBuilder equivalente?
Estoy usando Dropwizard Hibernate y tengo problemas con mis pruebas. He simplificado este ejemplo tanto como he podido. Creo un Foo
, lo actualizo y luego intento recuperarlo. El uso de una consulta sin formato obtiene el resultado correcto, pero la consulta equivalente CriteriaBuilder no detecta la actualización. ¿Qué estoy haciendo mal?
@Test
public void testFoo() {
String id = "12345";
// Create
Foo foo = Foo.builder()
.id(id)
.name("old-name")
.build();
sessionFactory.getCurrentSession().replicate(foo, ReplicationMode.EXCEPTION);
// Update
database.inTransaction(() -> {
CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaUpdate<Foo> update = cb.createCriteriaUpdate(Foo.class);
Root<Foo> root = update.from(Foo.class);
update.set(Foo_.name, "new-name");
update.where(cb.equal(root.get(Foo_.id), id));
int updated = sessionFactory.getCurrentSession().createQuery(update).executeUpdate();
});
// Select
database.inTransaction(() -> {
sessionFactory.getCurrentSession().flush(); // Not sure if this matters
String newName = (String) sessionFactory.getCurrentSession()
.createQuery("select name from Foo where id=:id")
.setParameter("id", id)
.getSingleResult();
assertEquals("new-name", newName);
log.error("New name is " + newName);
CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> root = cq.from(Foo.class);
cq.where(cb.equal(root.get(Foo_.id), id));
Query query = sessionFactory.getCurrentSession().createQuery(cq);
Foo foo2 = (Foo) query.getSingleResult();
log.error("New name is " + foo2.getName()); // Prints "old-name"
});
}
Aquí está mi código de configuración:
@ExtendWith(DropwizardExtensionsSupport.class)
public class UpdateTest {
private SessionFactory sessionFactory;
public DAOTestExtension database = DAOTestExtension.newBuilder()
.addEntityClass(Foo.class)
.build();
@BeforeEach
public void setup() {
sessionFactory = database.getSessionFactory();
}
...
}
También puedo mostrar la Foo
clase, pero no es muy interesante.
Respuestas
La Foo
instancia todavía está en la caché L1, es decir, la sesión actual que no es afectada por la declaración de actualización. Dado que Hibernate / JPA tiene que conservar la identidad de los objetos de entidad de una sesión, no puede borrar la sesión debido a la declaración de actualización. Por lo general, hay que borrar la sesión o actualizar las instancias después de una declaración de actualización para reflejar el estado actual nuevamente.
Intente hacerlo sessionFactory.getCurrentSession().clear();
al comienzo de su transacción de lectura