Mengapa kueri JQL saya mengembalikan hasil yang berbeda dari kueri CriteriaBuilder yang setara?

Aug 17 2020

Saya menggunakan Dropwizard Hibernate dan mengalami masalah dengan pengujian saya. Saya telah menyederhanakan contoh ini sebanyak mungkin. Saya membuat Foo, memperbaruinya, dan kemudian mencoba untuk mengambilnya. Menggunakan kueri mentah mendapatkan hasil yang benar, tetapi kueri CriteriaBuilder yang setara tidak menangkap pembaruan. Apa yang saya lakukan salah?

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

Ini kode penyiapan saya:

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

Saya juga bisa menunjukkan Fookelasnya, tapi itu tidak terlalu menarik.

Jawaban

1 ChristianBeikov Aug 18 2020 at 09:16

The Foocontoh masih dalam cache L1 yaitu sesi saat ini yang tidak tersentuh oleh pernyataan update. Sejak Hibernate / JPA harus mempertahankan identitas untuk objek entitas sesi, itu tidak dapat menghapus sesi karena pernyataan pembaruan. Biasanya, seseorang harus menghapus sesi atau me-refresh instance setelah pernyataan pembaruan untuk mencerminkan keadaan saat ini lagi.

Coba lakukan sessionFactory.getCurrentSession().clear();sebagai gantinya di awal transaksi baca Anda