You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Kevin Cox <kc...@att.com> on 2008/10/08 04:58:07 UTC

How to annotate a positional List

Hi,
I have been searching the manual, examples, and mail lists for an
implementation of a List, where the items in the list are positional stable
after the commit.  I¹ve had no luck and I am now wondering if it exists.  I
imagine it would need to otherwise nobody could properly store an ArrayList
using OpenJPA!  (should be basic stuff) Hibernate does this using
<list-index column="position"/>

Here¹s the problem.  Let¹s say I have a contrived Book object which has a
List (ArrayList) of pages (Page objects).  The pages in the List need to
maintain their order. Page 1,2,3,4 etc.  The order is maintained by using a
position or sequence number which is used to sort the list.

The db scheme would be something like

Create table book (
    book_id number,
    title varchar
)

Create table page (
    page_id number,
    page_data clob
)

And here¹s the link table

Create table book_page (
    book_id number,
    page_id number,
    sequence number  <<<<--- the position or sequence number 1,2,3,4,5,etc
) -- all not null

The Collection annotations for List need to automatically insert and update
the sequence numbers to make the ArrayList maintain stable order upon
commits.  The sequence needs to be incremented and decremented for List adds
and removes and renumbered for mid-list insertions and removes.

Does anyone know how to implement this in OpenJPA?  Is it supported?  It¹s
really just maps a java List to a db schema, keeping the list items order
stable during persistence.

Thanks,
Kevin

Re: How to annotate a positional List

Posted by Jeremy Bauer <te...@gmail.com>.
Kevin,

I opened JIRA OPENJPA-743
(https://issues.apache.org/jira/browse/OPENJPA-743) for the issue you
discovered where an OptimisticLockException is thrown when the Lob
field was not being set.  Apparently, when statement batching is
enabled, Oracle does not like the mix of parameter types/values
OpenJPA provides for null vs. non-null Lob fields.  I'll look into the
issue and hope to resolve it soon.  Until a fix is available, if you
need to store null values in a Lob field you may need to disable
statement batching.  The JIRA has details for disabling statement
batching.

-Jeremy

Re: How to annotate a positional List

Posted by Jeremy Bauer <te...@gmail.com>.
Hi Kevin,

Thanks for posting new code.  This last set of code explains why I
didn't see the updates.  My test used the same entity manager
throughout, while the code above creates a new EM for the remove
operation.  I also saw the updates using the code above, but only if I
used runtime entity enhancement (on by default in 1.2.0).  When I used
the javaagent or build-time enhancer, I no longer saw the updates.
OpenJPA can do a better job of tracking state with build time or
javaagent enhanced entities.

In regards to the double update operation, check to see if the last
update is really an update.  By default, OpenJPA does statement
batching with Oracle so the last update entry you are be seeing may
look like a duplicate, but in fact it is simply a report that the full
batch update is being executed:

For example: (batch two statements, then execute - the execute looks
like a duplicate update)

4548  MapPU  TRACE  [main] openjpa.jdbc.SQL - <t 26506390, conn
1309601> batching prepstmnt 8546123 UPDATE ORAUSER.PAGEOFBOOK SET DATA
= ? WHERE ID = ? [params=(Reader) java.io.StringReader@1b17d49, (long)
120]
4548  MapPU  TRACE  [main] openjpa.jdbc.SQL - <t 26506390, conn
1309601> [0 ms] spent
4548  MapPU  TRACE  [main] openjpa.jdbc.SQL - <t 26506390, conn
1309601> batching prepstmnt 8546123 UPDATE ORAUSER.PAGEOFBOOK SET DATA
= ? WHERE ID = ? [params=(Reader) java.io.StringReader@1fe4169, (long)
123]
4548  MapPU  TRACE  [main] openjpa.jdbc.SQL - <t 26506390, conn
1309601> [0 ms] spent
4548  MapPU  TRACE  [main] openjpa.jdbc.SQL - <t 26506390, conn
1309601> executing batch prepstmnt 8546123 UPDATE ORAUSER.PAGEOFBOOK
SET DATA = ? WHERE ID = ? [params=(Reader)
java.io.StringReader@1fe4169, (long) 123]

In short, make sure you are using the build-time or javaagent enhancer
and if you still see updates check the last update to see if it says
"executing batch prepstmt" vs. "batching prepstmt".

-Jeremy

Re: How to annotate a positional List

Posted by Kevin Cox <kc...@att.com>.
For the persistence.xml - no special settings, just a persistence-unit and a
list of classes.  For the Persistence object, I just have normal user and
password with a db url plus the following:
p.put("openjpa.jdbc.SynchronizeMappings","buildSchema");
p.put("openjpa.Log","DefaultLevel=WARN,SQL=TRACE"); //Runtime=TRACE
Nothing else...

Conditions:
DB is Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit
Production, using driver named ojdbc14.jar
OpenJPA is 1.2.0
Running through IntelliJ IDEA 8.0M1 set to java 1.6
On a Mac Pro Intel OS X 10.5.5

If I missed something important let me know.  I'm happy to help and happy
you are helping me ;)

file: Book.java
--------------------------------------------------------------------------
package com.play.cmsdata;

import org.apache.openjpa.persistence.jdbc.OrderColumn;
import org.apache.openjpa.persistence.PersistentCollection;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity
@SequenceGenerator(name="BookSeq", sequenceName="BOOK_SEQ")
public class Book {
   @Id @GeneratedValue(strategy= GenerationType.TABLE, generator="BookSeq")
   private long id;

   String title;

   @PersistentCollection(elementCascade=CascadeType.ALL)
   @OrderColumn
   private List<PageOfBook> pages = new ArrayList<PageOfBook>();

    public Book() {
    }

    public Book(long id) {
        this.id = id;
    }

    public Book(String title) {
        this.title = title;
    }

    public long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<PageOfBook> getPages() {
        return pages;
    }

    public void setPages(List<PageOfBook> pages) {
        this.pages = pages;
    }
}



file: Book.java
--------------------------------------------------------------------------
package com.play.cmsdata;

import javax.persistence.*;
import javax.persistence.Lob;
import javax.persistence.GeneratedValue;


@Entity
@SequenceGenerator(name="PageOfBookSeq", sequenceName="PAGEOFBOOK_SEQ")
public class PageOfBook {
   @Id @GeneratedValue(strategy= GenerationType.TABLE,
generator="PageOfBookSeq")
   private long id;

   @Lob
   private String data;

    public PageOfBook() {
    }

    public long getId() {
        return id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}



--------------------------------------------------------------------------


I use the following to manipulate the data.  I play with the comments in
removePage() to do the removes and remove/inserts.  Ya crude, I know.

private static void createBook() {
        EntityManager em =MyPersistence.getInstance().createEntityManager();
        em.getTransaction().begin();

        PageOfBook p1 = new PageOfBook();
        p1.setData("This is a page 1 in a book");

        PageOfBook p2 = new PageOfBook();
        p2.setData("This is a page 2 in a book");

        Book b = new Book("My Book Example for Lists");
        b.getPages().add(p1);
        b.getPages().add(p2);

        em.persist(b);
        em.getTransaction().commit();


        em.getTransaction().begin();
        Book book = em.find(Book.class, 1L);

        PageOfBook p3 = new PageOfBook();
        p3.setData("This is a page 3 in a book");
        PageOfBook p4 = new PageOfBook();
        p4.setData("This is a page 4 in a book");
        book.getPages().add(p3);
        book.getPages().add(p4);
        em.getTransaction().commit();

//another tx just because
        em.getTransaction().begin();
        book = em.find(Book.class, 1L);

        PageOfBook p5 = new PageOfBook();
        p5.setData("This is a page 5 in a book");
        book.getPages().add(p5);

        em.getTransaction().commit();
        em.close();
    }
    private static void removePage() {
        EntityManager em =MyPersistence.getInstance().createEntityManager();
        em.getTransaction().begin();

        Book book = em.find(Book.class, 1L);
//uncomment the parts you want to run
        //book.getPages().remove(2); //which is item 3 in the array
        
        //PageOfBook p7 = new PageOfBook();
        //p7.setData("This is a page 7 in a book");
        //book.getPages().add(2,p7);

        em.getTransaction().commit();
        em.close();
    }


Re: How to annotate a positional List

Posted by Jeremy Bauer <te...@gmail.com>.
Hi Kevin,

I was surprised to see updates in your SQL output, since you are
simply adding and removing entries from the list.  My test (also using
OpenJPA 1.2.0) did not produce any update statements, only inserts and
deletes.  From the SQL appears that the data field is changing between
commits?  If you could post a new version of your test code, that may
help - including entity classes, if those have changed.  Also, do you
have any extra Oracle dictionary related or other openjpa properties
beyond the standard datasource config properties in your
persistence.xml?

PS, I haven't dug into the optimistic lock exception yet.  I'll post
as soon as I have any details.

-Jeremy

Re: How to annotate a positional List

Posted by Kevin Cox <kc...@att.com>.
Hi Jeremy, 
It looks like you are correct on the LOB data being null.  That manifesting
itself as an optimistic lock exception is odd.  And, thanks for catching my
error.

I ran the rest of my (non-thorough) tests to prove out the usage of
@PersistentCollection(elementCascade=CascadeType.ALL,fetch=FetchType.EAGER)
@OrderColumn
        
Below, I show the content of the Book_PageOfBook table after each
modification to the list.  The results are correct!  And, when inserting,
the implementation renumbers the list exactly as expected.

I also show the SQL statements associated to each step.  There might be a
bug here, however.  Notice that the last update statement that modifies the
list is repeated.  It's a non-damaging bug, but incorrect nonetheless.
Could be a trace logging error - I'm not sure.
Anyone have ideas on why the last update statement repeats?

The following steps happen in sequence.

Initial creation of book and 5 pages
--------------------------------------------------------------
as shown previously with Jeremy's bug fix help on the p3 to p4 variable name
screw up
BOOK_ID    PAGES_ID    ORDR
1    1    0
1    2    1
1    4    2
1    3    3
1    5    4

book.getPages().remove(2L) which is the 3rd item
--------------------------------------------------------------
em.getTransaction().begin();
Book book = em.find(Book.class, 1L);
book.getPages().remove(2); //which is item 3 in the array
em.getTransaction().commit();

BOOK_ID    PAGES_ID    ORDR
1    1    0
1    2    1
1    3    3
1    5    4

book.getPages().remove(2L) again with adding a page 6
--------------------------------------------------------------
em.getTransaction().begin();
Book book = em.find(Book.class, 1L);
book.getPages().remove(2); //which is item 3 in the array
PageOfBook p6 = new PageOfBook();
p6.setData("This is a page 6 in a book");
book.getPages().add(p6);
em.getTransaction().commit();
1    1    0
1    2    1
1    5    4
1    6    5


book.getPages().add(2,p7)  inserting page 7 at position 2, 3rd position
--------------------------------------------------------------
em.getTransaction().begin();
Book book = em.find(Book.class, 1L);
PageOfBook p7 = new PageOfBook();
p7.setData("This is a page 7 in a book");
book.getPages().add(2,p7);
em.getTransaction().commit();
BOOK_ID    PAGES_ID    ORDR
1    1    0
1    2    1
1    7    2
1    5    3
1    6    4


book.getPages().remove(2L)
--------------------------------------------------------------
SELECT t0.ordr, t1.id, t1.data FROM Book_PageOfBook t0, PageOfBook t1 WHERE
t0.BOOK_ID = ? AND t0.PAGES_ID = t1.id ORDER BY t0.ordr ASC [params=(long)
1]
DELETE FROM Book_PageOfBook WHERE BOOK_ID = ? AND PAGES_ID = ?
[params=(long) 1, (long) 4]
UPDATE Book SET title = ? WHERE id = ? [params=(String) My Book Example for
Lists, (long) 1]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@1a996ff, (long) 4]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@256a4d0a, (long) 2]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@2f13f599, (long) 1]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@4ea10ca8, (long) 5]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@4fc063f6, (long) 3]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@4fc063f6, (long) 3]
>>> LOOK: the last two updates for id=3 is repeated at the end.


book.getPages().remove(2L) again with adding a page 6
--------------------------------------------------------------

DELETE FROM Book_PageOfBook WHERE BOOK_ID = ? AND PAGES_ID = ?
[params=(long) 1, (long) 3]
INSERT INTO PageOfBook (id, data) VALUES (?, ?) [params=(long) 6, (Reader)
java.io.StringReader@45eb96fc]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@ef2106b, (long) 3]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@68dfb213, (long) 2]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@68dfb213, (long) 2]
UPDATE Book SET title = ? WHERE id = ? [params=(String) My Book Example for
Lists, (long) 1]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@18ba689b, (long) 5]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@7bc1d0fa, (long) 1]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@7bc1d0fa, (long) 1]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 6, (int) 5]
>>> LOOK: the last two updates for id=1 is repeated at the end.


book.getPages().add(2,p7)  inserting page 7 at position 2
--------------------------------------------------------------
DELETE FROM Book_PageOfBook WHERE BOOK_ID = ? [params=(long) 1]
INSERT INTO PageOfBook (id, data) VALUES (?, ?) [params=(long) 7, (Reader)
java.io.StringReader@3e0e5c40]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@42de7804, (long) 1]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@7ebd6a19, (long) 5]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@24aa663f, (long) 6]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@11b2c43e, (long) 2]
UPDATE PageOfBook SET data = ? WHERE id = ? [params=(Reader)
java.io.StringReader@11b2c43e, (long) 2]
UPDATE Book SET title = ? WHERE id = ? [params=(String) My Book Example for
Lists, (long) 1]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 1, (int) 0]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 2, (int) 1]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 7, (int) 2]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 5, (int) 3]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 6, (int) 4]
INSERT INTO Book_PageOfBook (BOOK_ID, PAGES_ID, ordr) VALUES (?, ?, ?)
[params=(long) 1, (long) 6, (int) 4]
>>> LOOK: the last two updates for page_id 6 and ordr=4 is repeated at the end.


Re: How to annotate a positional List

Posted by Jeremy Bauer <te...@gmail.com>.
Hi Kevin.

I'm glad to see OrderColumn may work for you.  There's a small bug in
the code above that is causing the optimistic lock exception.

PageOfBook p3 = new PageOfBook();
p3.setData("This is a page 3 in a book");
PageOfBook p4 = new PageOfBook();
p3.setData("This is a page 4 in a book");

Notice that the second setData is on p3 instead of p4.  After I
changed it to p4, the test ran OK.  I'm not sure why this is resulting
in an optimistic lock exception since that seems a bit misleading.  It
looks to be directly related to having null data in your lob data
field though.  I'll take a closer look and possibly open a JIRA.

-Jeremy

Re: How to annotate a positional List

Posted by Kevin Cox <kc...@att.com>.
Andy, thanks for you input.
I am trying your last solution.  The actual classes are shown below.  The DB
is oracle 10g.  I am running the test using the following code to create a
book then looking up the book and trying to add a couple pages.  The SQL
generate is exactly as you suspected and shown below.  I get an Optimistic
locking error when trying to commit the updates (added pages).  Do you see
what might be wrong?

//First, just create a book and a couple pages - works fine
EntityManager em = MyPersistence.getInstance().createEntityManager();
em.getTransaction().begin();

PageOfBook p1 = new PageOfBook();
p1.setData("This is a page 1 in a book");

PageOfBook p2 = new PageOfBook();
p2.setData("This is a page 2 in a book");

Book b = new Book("My Book Example for Lists");
b.getPages().add(p1);
b.getPages().add(p2);

em.persist(b);
em.getTransaction().commit();

//WORKS GREAT UP TO HERE - RECORDS GET WRITTEN TO DB AND OrderColumn is
creating a numbered sequence!

//Now, I am testing if I can add to the list, look up the saved book
em.getTransaction().begin();
//Query q3 = em.createQuery("SELECT book from Book book where book.id =
?1");
//q3.setParameter(1,1L);
//Book book = (Book) q3.getSingleResult();
BOTH THE QUERY AND THE EM.FIND RESULT IN Optimistic locking error exception

Book book = em.find(Book.class, 1L);

PageOfBook p3 = new PageOfBook();
p3.setData("This is a page 3 in a book");
PageOfBook p4 = new PageOfBook();
p3.setData("This is a page 4 in a book");
book.getPages().add(p3);
book.getPages().add(p4);

em.getTransaction().commit();
//on this commit, I get
Exception in thread "main" <openjpa-1.2.0-r422266:683325 fatal store error>
org.apache.openjpa.persistence.RollbackException: Optimistic locking errors
were detected when flushing to the data store.  The following objects may
have been concurrently modified in another transaction:
[com.play.cmsdata.PageOfBook@5f55b990, com.play.cmsdata.PageOfBook@4319b06e]
    at 
org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.ja
va:523)
    at hellojpa.Main.createBook(Main.java:122)
    at hellojpa.Main.main(Main.java:37)
Caused by: <openjpa-1.2.0-r422266:683325 nonfatal store error>
org.apache.openjpa.persistence.OptimisticLockException: Optimistic locking
errors were detected when flushing to the data store.  The following objects
may have been concurrently modified in another transaction:
[com.play.cmsdata.PageOfBook@5f55b990, com.play.cmsdata.PageOfBook@4319b06e]
    at 
org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2160)
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2010)
    at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:1908)
    at 
org.apache.openjpa.kernel.BrokerImpl.beforeCompletion(BrokerImpl.java:1826)
    at 
org.apache.openjpa.kernel.LocalManagedRuntime.commit(LocalManagedRuntime.jav
a:81)
    at org.apache.openjpa.kernel.BrokerImpl.commit(BrokerImpl.java:1350)
    at 
org.apache.openjpa.kernel.DelegatingBroker.commit(DelegatingBroker.java:877)
    at 
org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.ja
va:512)
    ... 2 more
Caused by: <openjpa-1.2.0-r422266:683325 nonfatal store error>
org.apache.openjpa.persistence.OptimisticLockException: An optimistic lock
violation was detected when flushing object instance
"com.play.cmsdata.PageOfBook@5f55b990" to the data store.  This indicates
that the object was concurrently modified in another transaction.
FailedObject: com.play.cmsdata.PageOfBook@5f55b990

em.close();


-----------------------------------------------------------
import org.apache.openjpa.persistence.jdbc.OrderColumn;
import org.apache.openjpa.persistence.PersistentCollection;

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Entity
@SequenceGenerator(name="BookSeq", sequenceName="BOOK_SEQ")
public class Book {
   @Id @GeneratedValue(strategy= GenerationType.TABLE, generator="BookSeq")
   private long id;

   String title;

   @PersistentCollection(elementCascade=CascadeType.ALL)
   @OrderColumn
   private List<PageOfBook> pages = new ArrayList<PageOfBook>();

    public Book() {
    }

    public Book(long id) {
        this.id = id;
    }

    public Book(String title) {
        this.title = title;
    }

    public long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<PageOfBook> getPages() {
        return pages;
    }

    public void setPages(List<PageOfBook> pages) {
        this.pages = pages;
    }
}


-----------------------------------------------------------
import javax.persistence.*;
import javax.persistence.Lob;
import javax.persistence.GeneratedValue;

@Entity
@SequenceGenerator(name="PageOfBookSeq", sequenceName="PAGEOFBOOK_SEQ")
public class PageOfBook {
   @Id @GeneratedValue(strategy= GenerationType.TABLE,
generator="PageOfBookSeq")
   private long id;

   @Lob
   private String data;

    public PageOfBook() {
    }

    public long getId() {
        return id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}


Here are the actual generated tables (from sql trace):
CREATE TABLE Book (id NUMBER NOT NULL, title VARCHAR2(255), PRIMARY KEY
(id))
CREATE TABLE Book_PageOfBook (BOOK_ID NUMBER, PAGES_ID NUMBER, ordr NUMBER)
CREATE TABLE PageOfBook (id NUMBER NOT NULL, data CLOB, PRIMARY KEY (id))


Re: How to annotate a positional List

Posted by Andy Schlaikjer <ha...@cs.cmu.edu>.
Hi Kevin,

 From your example table schema, it looks as though you would like to be 
able to reference the same page from more than one book. I had a similar 
problem ages ago, but found that it wasn't possible to do this easily 
with JPA because there is no way to have the @OrderBy annotation target 
a column within a @JoinTable. The column which @OrderBy points to must 
be present in the target entity's table, which can't be the case if the 
intended relation is a true many-to-many. My prior solution was to 
pollute my domain model with an extra "join" entity class which would 
map to the desired join table directly (including the sequence column 
explicitly).

However, with OpenJPA's @OrderColumn extension, I believe this is now 
possible:

@Entity
public class Book {
   @Id
   private long id;

   @PersistentCollection
   @OrderColumn
   private List<Page> pages;
}

@Entity
public class Page {
   @Id
   private long id;

   @Lob
   private string data;
}

The generated DDL using OpenJPA 1.2.0 and MySQL DBDictionary is:

CREATE TABLE Book (id BIGINT NOT NULL, PRIMARY KEY (id))
CREATE TABLE Book_Page (BOOK_ID BIGINT, PAGES_ID BIGINT, ordr INTEGER)
CREATE TABLE Page (id BIGINT NOT NULL, data TEXT, PRIMARY KEY (id))

Cheers,
Andy

Kevin Cox wrote:
> Hi,
> I have been searching the manual, examples, and mail lists for an
> implementation of a List, where the items in the list are positional stable
> after the commit.  I¹ve had no luck and I am now wondering if it exists.  I
> imagine it would need to otherwise nobody could properly store an ArrayList
> using OpenJPA!  (should be basic stuff) Hibernate does this using
> <list-index column="position"/>
> 
> Here¹s the problem.  Let¹s say I have a contrived Book object which has a
> List (ArrayList) of pages (Page objects).  The pages in the List need to
> maintain their order. Page 1,2,3,4 etc.  The order is maintained by using a
> position or sequence number which is used to sort the list.
> 
> The db scheme would be something like
> 
> Create table book (
>     book_id number,
>     title varchar
> )
> 
> Create table page (
>     page_id number,
>     page_data clob
> )
> 
> And here¹s the link table
> 
> Create table book_page (
>     book_id number,
>     page_id number,
>     sequence number  <<<<--- the position or sequence number 1,2,3,4,5,etc
> ) -- all not null
> 
> The Collection annotations for List need to automatically insert and update
> the sequence numbers to make the ArrayList maintain stable order upon
> commits.  The sequence needs to be incremented and decremented for List adds
> and removes and renumbered for mid-list insertions and removes.
> 
> Does anyone know how to implement this in OpenJPA?  Is it supported?  It¹s
> really just maps a java List to a db schema, keeping the list items order
> stable during persistence.
> 
> Thanks,
> Kevin
> 


Re: How to annotate a positional List

Posted by Jeremy Bauer <te...@gmail.com>.
Until a standardized method for ordered lists is defined by the spec,
the org.apache.openjpa.persistence.jdbc.OrderColumn annotation (in
possibly combination with other  OpenJPA specific collection
annotations) may be an option.  Take a look at the unit test

openjpa-persistence-jdbc\src\test\java\org\apache\openjpa\persistence\jdbc\annotations\NonstandardMappingEntity.java

for example usage.

-Jeremy

Re: How to annotate a positional List

Posted by Judes Tumuhairwe <ju...@gmail.com>.
Hi Kevin,
Ordered lists (where the order is important and persistible) are not part of
the JPA 1.0 spec. They are planned for the JPA 2.0 spec.
Linda DeMichiel (the JPA spec lead @ Sun) gave an overview of it at the
JavaOne this year [1] (page 22+ of the PDF presentation/slides talk about
it).
Since the spec is not yet final, I doubt that OpenJPA implements it but I
could be wrong (can anyone from the dev-team confirm this or give an
estimated date if planned?).

[1]
http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-5509&yr=2008&track=javaee


Judes Tumuhairwe
jtumuha1@ford.com

On Tue, Oct 7, 2008 at 10:58 PM, Kevin Cox <kc...@att.com> wrote:

> Hi,
> I have been searching the manual, examples, and mail lists for an
> implementation of a List, where the items in the list are positional stable
> after the commit.  I¹ve had no luck and I am now wondering if it exists.  I
> imagine it would need to otherwise nobody could properly store an ArrayList
> using OpenJPA!  (should be basic stuff) Hibernate does this using
> <list-index column="position"/>
>
> Here¹s the problem.  Let¹s say I have a contrived Book object which has a
> List (ArrayList) of pages (Page objects).  The pages in the List need to
> maintain their order. Page 1,2,3,4 etc.  The order is maintained by using a
> position or sequence number which is used to sort the list.
>
> The db scheme would be something like
>
> Create table book (
>    book_id number,
>    title varchar
> )
>
> Create table page (
>    page_id number,
>    page_data clob
> )
>
> And here¹s the link table
>
> Create table book_page (
>    book_id number,
>    page_id number,
>    sequence number  <<<<--- the position or sequence number 1,2,3,4,5,etc
> ) -- all not null
>
> The Collection annotations for List need to automatically insert and update
> the sequence numbers to make the ArrayList maintain stable order upon
> commits.  The sequence needs to be incremented and decremented for List
> adds
> and removes and renumbered for mid-list insertions and removes.
>
> Does anyone know how to implement this in OpenJPA?  Is it supported?  It¹s
> really just maps a java List to a db schema, keeping the list items order
> stable during persistence.
>
> Thanks,
> Kevin
>