Why does my JQL query return a different result than the equivalent CriteriaBuilder query?

馋奶兔 提交于 2020-08-20 12:09:39

问题


I'm using Dropwizard Hibernate and am having issues with my tests. I've simplified this example as much as possible. I create a Foo, update it, and then try to fetch it. Using a raw query gets the correct result, but the equivalent CriteriaBuilder query doesn't catch the update. What am I doing wrong?

    @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"
        });
    }

Here's my setup code:

@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();
    }
...
}

I can also show the Foo class, but it's not very interesting.


回答1:


The Foo instance is still in the L1 cache i.e. the current session which is not touched by the update statement. Since Hibernate/JPA has to retain identity for entity objects of a session, it can't clear the session due to the update statement. Usually, one has to clear the session or refresh instances after an update statement to reflect the current state again.

Try doing sessionFactory.getCurrentSession().clear(); instead at the start of your read transaction



来源:https://stackoverflow.com/questions/63457714/why-does-my-jql-query-return-a-different-result-than-the-equivalent-criteriabuil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!