Zoltán Haindrich
Zoltán Haindrich

Reputation: 1808

eclipselink, advanced query doesn't work as expected

i'm using eclipselink for jpa, and the iterator worked strangely... after fixing it by not using the advanced query api i tryed narrow down the problem. it looks like i might be completely misunderstood something in the manual...why the following two queries has different results?

the problematic piece of code is this:

        if (useAdvancedQuery) {
            // doesn't write to db
            ReadAllQuery readAllQuery = new ReadAllQuery(type);
            readAllQuery.useCursoredStream(500, 500);
            Session session = em.unwrap(Session.class);
            scrollableCursor = (CursoredStream) session
                    .executeQuery(readAllQuery);
        } else {
            Query query = em.createQuery("SELECT e FROM " + type.getName()
                    + " e ORDER BY e.id Desc");
            query.setHint("eclipselink.cursor", true);
            query.setHint("eclipselink.cursor.page-size", 50);
            scrollableCursor = (CursoredStream) query.getSingleResult();
        }

if useAdvancedQuery==false then everything works as expected

if i enable useAdvancedQuery then it fails...but in a very strange way:

i've written a one-file example for the problem:

package x;

import java.io.Serializable;
import java.util.*;

import javax.persistence.*;

import junit.framework.Assert;

import org.eclipse.persistence.queries.*
import org.eclipse.persistence.sessions.Session;

@Entity
public class TestEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id;

    private String label;

    private static final long serialVersionUID = 1L;

    TestEntity() {
    }

    public TestEntity(String l) {
        setLabel(l);
    }

    public static void main(String[] args) throws ClassNotFoundException {
        new Extracted().run();
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    static class Extracted {

        // tweakables
        boolean useAdvancedQuery = true;
        boolean useNewEntityManagers = false;

        public <T> Iterator<T> getIterator(Class<T> type) {

            final CursoredStream scrollableCursor;

            // change this to false..and it will pass

            if (useAdvancedQuery) {
                // doesn't write to db
                ReadAllQuery readAllQuery = new ReadAllQuery(type);
                readAllQuery.useCursoredStream(500, 500);
                Session session = em.unwrap(Session.class);
                scrollableCursor = (CursoredStream) session
                        .executeQuery(readAllQuery);
            } else {
                Query query = em.createQuery("SELECT e FROM " + type.getName()
                        + " e ORDER BY e.id Desc");
                query.setHint("eclipselink.cursor", true);
                query.setHint("eclipselink.cursor.page-size", 50);
                scrollableCursor = (CursoredStream) query.getSingleResult();
            }

            return new Iterator<T>() {

                @Override
                public boolean hasNext() {
                    return scrollableCursor.hasMoreElements();
                }

                @Override
                public T next() {
                    if (!scrollableCursor.hasMoreElements()) {
                        return null;
                    }
                    scrollableCursor.clear();
                    @SuppressWarnings("unchecked")
                    T c = (T) scrollableCursor.next();
                    return c;
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            };
        }


        private EntityManagerFactory emf;
        private EntityManager em;

        public void run() {

            {
                emf = Persistence.createEntityManagerFactory("ptx2");
                em = emf.createEntityManager();

                em.getTransaction().begin();
                em.persist(new TestEntity("a"));
                em.persist(new TestEntity("c"));
                em.persist(new TestEntity("d"));
                em.getTransaction().commit();

                System.out.println("asd!");
                em.close();
                if (useNewEntityManagers)
                    emf.close();
            }

            String testStr = "tst" + new Random().nextInt();
            {
                if (useNewEntityManagers)
                    emf = getEntityManager();
                em = emf.createEntityManager();
                em.getTransaction().begin();
                Iterator<TestEntity> it = getIterator(TestEntity.class);
                while (it.hasNext()) {
                    TestEntity e = it.next();
                    e.setLabel(testStr);
                    // em.merge(e);
                }
                em.getTransaction().commit();
                em.close();
                if (useNewEntityManagers)
                    emf.close();
            }
            {
                if (useNewEntityManagers)
                    emf = getEntityManager();
                checkConsistance(testStr);
                System.out.println("persisted in current session - ok");
                emf.close();
            }
            {
                System.out.println("persisted after reconnect?");
                emf = getEntityManager();
                checkConsistance(testStr);
                emf.close();
            }
            System.out.println("passed");
        }

        private void checkConsistance(String testStr) {
            em = emf.createEntityManager();
            em.getTransaction().begin();
            Iterator<TestEntity> it = getIterator(TestEntity.class);
            while (it.hasNext()) {
                TestEntity e = it.next();
                Assert.assertEquals(testStr, e.getLabel());
            }
            em.close();
        }
    }

    private static EntityManagerFactory getEntityManager() {
        return Persistence.createEntityManagerFactory("ptx2");
    }

}

note: i'm using Eclipselink-2.5.0.v20130507-3faac2b

Upvotes: 1

Views: 2016

Answers (1)

Chris
Chris

Reputation: 21145

The session you are unwrapping gives access to the second level cache; it will return objects that are meant to be read-only and should not be changed. Any changes to these objects are not tracked, and since they are the objects from the shared cache, are immediately visible to other threads.

What you should be getting is the UnitOfWork which will return managed entities.

Upvotes: 1

Related Questions