You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Tim Watts <ti...@cliftonfarm.org> on 2011/10/12 03:05:22 UTC

how to get db generated values on persist

Hello,

I'm sure this problem comes down to me not fully groking the JPA way:
Using OpenJPA (2.0.1), how do I get a call to persist() to automatically
populate non-nullable, non-key fields whose values are generated by the
database? Here are the particulars:

DDL:
	modified     timestamp  not null  default current_timestamp,

Entity:
	@Temporal (TemporalType.TIMESTAMP)
	@Column (insertable=false, updatable=false)
	private Calendar modified;

Relevant JPA Property:
	openjpa.AutoDetach=close,commit,nontx-read

Databases:
	PostgreSQL 8.4, Derby 10.8

Test (which fails):
	...{set fields, but not 'modified'}...
	et = em.getTransaction();
	et.begin();
	em.persist(entity);
	et.commit();
	assertNotNull(entity.getModified());

A query on the table, of course, shows a value for modified.

Some things I've tried that haven't worked:
      * Immediately after persist, entity.getModified();
      * Immediately after persist, em.refresh(entity);

On a possibly related note, I'm puzzled as to why I'm seeing the
following message when I run my tests despite the fact that I'm running
the enhancer on my domain classes via the openjpa-maven-plugin
(codehaus):

        INFO   [main] openjpa.Enhance - You have enabled runtime
        enhancement, but have not specified the set of persistent
        classes. ...

I've inspected the .class file and it has a pcGetmodified among other
things. So it looks like the classes are indeed getting enhanced.

Any insights? Do I need a post processor to populate 'modified'?



Re: how to get db generated values on persist

Posted by Tim Watts <ti...@cliftonfarm.org>.
Thanks Miłosz. Yes, that worked. Guess I was reading the documentation
too rigidly.

But I think I'm going to stick with @PrePersist, @PreUpdate because I
also have a 'created' field which should be set once. I suppose I could
add a constraint or trigger to enforce this but I've got something
working now and I need to move on. Thanks again for the input. I'll note
it for future reference.


On Sun, 2011-10-16 at 14:58 +0200, Miłosz Tylenda wrote:
> Tim,
> 
> You can apply @GeneratedValue to a field which is generated by the database even if the field is not a primary key. The following did work for me on PostgreSQL:
> 
> create table gv_test(id bigserial, modified timestamp not null default current_timestamp, vvv int)
> 
> @Entity
> @Table(name="gv_test")
> public class Message {
>     @Id
>     @GeneratedValue(strategy=GenerationType.IDENTITY)
>     private long id;
>     private Integer vvv;
>     @GeneratedValue(strategy=GenerationType.IDENTITY)
>     private Date modified;
> 
>     public Message() {
>     }
> 
>     public Message(Integer v) {
>         vvv = v;
>     }
> 
>     public long getId() {
>         return id;
>     }
>     
>     public void setId(long val) {
>         id = val;
>     }
> 
>     public Date getModified() {
>         return modified;
>     }
> 
>     public void setModified(Date modified) {
>         this.modified = modified;
>     }
> 
>     public Integer getVvv() {
>         return vvv;
>     }
> 
>     public void setVvv(Integer vvv) {
>         this.vvv = vvv;
>     }
> }
> 
> 
> 
>         em.getTransaction().begin();
> 
>         Message m = new Message(60);
>         em.persist(m);
>         System.out.println(m.getModified());
> 
>         em.getTransaction().commit();
> 
> 
> Regards,
> Milosz
> 



Re: how to get db generated values on persist

Posted by Miłosz Tylenda <mt...@o2.pl>.
Tim,

You can apply @GeneratedValue to a field which is generated by the database even if the field is not a primary key. The following did work for me on PostgreSQL:

create table gv_test(id bigserial, modified timestamp not null default current_timestamp, vvv int)

@Entity
@Table(name="gv_test")
public class Message {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    private Integer vvv;
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Date modified;

    public Message() {
    }

    public Message(Integer v) {
        vvv = v;
    }

    public long getId() {
        return id;
    }
    
    public void setId(long val) {
        id = val;
    }

    public Date getModified() {
        return modified;
    }

    public void setModified(Date modified) {
        this.modified = modified;
    }

    public Integer getVvv() {
        return vvv;
    }

    public void setVvv(Integer vvv) {
        this.vvv = vvv;
    }
}



        em.getTransaction().begin();

        Message m = new Message(60);
        em.persist(m);
        System.out.println(m.getModified());

        em.getTransaction().commit();


Regards,
Milosz


Re: how to get db generated values on persist

Posted by Tim Watts <ti...@cliftonfarm.org>.
On Thu, 2011-10-13 at 06:09 -0700, Pinaki Poddar wrote:
> flush();
> 
Not following your drift. Instead of refresh()? Before commit()? Tried
both to no avail. Calling after commit(), of course, requires a new
transaction.

I should mention that my test uses a single EntityManager instance (but
not the same one across tests). That may not be typical for common
scenarios (e.g. web-container, non-jta). Even so, I did try closing and
creating a new EM and got the same results.

Like I said, I've more or less decided that setting the value
programmatically is probably the better way to go. But I can't imagine
that this is an exceptional situation (databases have had this
capability since at least the '90s) so I thought maybe there was some
annotation or property I was overlooking.


> -----
> Pinaki Poddar
> Chair, Apache OpenJPA Project
> --
> View this message in context: http://openjpa.208410.n2.nabble.com/how-to-get-db-generated-values-on-persist-tp6883308p6888838.html
> Sent from the OpenJPA Users mailing list archive at Nabble.com.



Re: how to get db generated values on persist

Posted by Pinaki Poddar <pp...@apache.org>.
flush();

-----
Pinaki Poddar
Chair, Apache OpenJPA Project
--
View this message in context: http://openjpa.208410.n2.nabble.com/how-to-get-db-generated-values-on-persist-tp6883308p6888838.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: how to get db generated values on persist

Posted by Tim Watts <ti...@cliftonfarm.org>.
Thank you Kevin.

I could not get it to work with refresh() but did get it working with
find(). However, it only worked after the object was first detached
(either by setting autoDetach or detach()ing it). Refresh() didn't work
even after detach(); entity=em.merge(); em.refresh(). In the end, I
found all this to be far too inefficient and wildly counter-intuitive
and decided to punt by setting the value myself with lifecycle hooks
rather than leverage the database's capabilities.

My expectation was that a call to persist() (upon commit()) should leave
the object and the datastore 100% consistent with each other. I don't
know enough to say whether this is a bug in OpenJPA, the JPA spec or my
expectations. Seems like there's a need for an @GeneratedField or
something that applies to non-key fields -- something that says "you
need to get the value from the datastore if the entity didn't provide
it". I don't know. I suppose if you're asking the database to generate a
value then you may be talking about a scenario where the user is done
with the object once it's inserted. But if the expectation is that the
user may do more work on the object that is later flushed to the
datastore then it makes more sense for the application to set those
values.  OK, I guess I talked myself out of it although I have to say I
feel better declaring a default value than having to code and annotate
for it. :-)

Thanks again.


On Wed, 2011-10-12 at 15:19 -0500, Kevin Sutter wrote:
> Hi Tim,
> Since the database is providing the value, you will need to do an explicit
> action to pull the values from the table.  Try doing the em.refresh(entity)
> after the commit call.  The em.persist() invocation does not push anything
> to the database until a flush() or commit() is performed.  So, there would
> be nothing to refresh from the database until the flush/commit is
> performed.  That should work for you.
> 
> Another idea is to do an em.find(), but since you have the entity handy, you
> should be able to get by with the refresh() call.
> 
> HTH,
> Kevin
> 
> On Tue, Oct 11, 2011 at 8:05 PM, Tim Watts <ti...@cliftonfarm.org> wrote:
> 
> > Hello,
> >
> > I'm sure this problem comes down to me not fully groking the JPA way:
> > Using OpenJPA (2.0.1), how do I get a call to persist() to automatically
> > populate non-nullable, non-key fields whose values are generated by the
> > database? Here are the particulars:
> >
> > DDL:
> >        modified     timestamp  not null  default current_timestamp,
> >
> > Entity:
> >        @Temporal (TemporalType.TIMESTAMP)
> >        @Column (insertable=false, updatable=false)
> >        private Calendar modified;
> >
> > Relevant JPA Property:
> >        openjpa.AutoDetach=close,commit,nontx-read
> >
> > Databases:
> >        PostgreSQL 8.4, Derby 10.8
> >
> > Test (which fails):
> >        ...{set fields, but not 'modified'}...
> >        et = em.getTransaction();
> >        et.begin();
> >        em.persist(entity);
> >        et.commit();
> >        assertNotNull(entity.getModified());
> >
> > A query on the table, of course, shows a value for modified.
> >
> > Some things I've tried that haven't worked:
> >      * Immediately after persist, entity.getModified();
> >      * Immediately after persist, em.refresh(entity);
> >
> > On a possibly related note, I'm puzzled as to why I'm seeing the
> > following message when I run my tests despite the fact that I'm running
> > the enhancer on my domain classes via the openjpa-maven-plugin
> > (codehaus):
> >
> >        INFO   [main] openjpa.Enhance - You have enabled runtime
> >        enhancement, but have not specified the set of persistent
> >        classes. ...
> >
> > I've inspected the .class file and it has a pcGetmodified among other
> > things. So it looks like the classes are indeed getting enhanced.
> >
> > Any insights? Do I need a post processor to populate 'modified'?
> >
> >
> >



Re: how to get db generated values on persist

Posted by Kevin Sutter <kw...@gmail.com>.
Hi Tim,
Since the database is providing the value, you will need to do an explicit
action to pull the values from the table.  Try doing the em.refresh(entity)
after the commit call.  The em.persist() invocation does not push anything
to the database until a flush() or commit() is performed.  So, there would
be nothing to refresh from the database until the flush/commit is
performed.  That should work for you.

Another idea is to do an em.find(), but since you have the entity handy, you
should be able to get by with the refresh() call.

HTH,
Kevin

On Tue, Oct 11, 2011 at 8:05 PM, Tim Watts <ti...@cliftonfarm.org> wrote:

> Hello,
>
> I'm sure this problem comes down to me not fully groking the JPA way:
> Using OpenJPA (2.0.1), how do I get a call to persist() to automatically
> populate non-nullable, non-key fields whose values are generated by the
> database? Here are the particulars:
>
> DDL:
>        modified     timestamp  not null  default current_timestamp,
>
> Entity:
>        @Temporal (TemporalType.TIMESTAMP)
>        @Column (insertable=false, updatable=false)
>        private Calendar modified;
>
> Relevant JPA Property:
>        openjpa.AutoDetach=close,commit,nontx-read
>
> Databases:
>        PostgreSQL 8.4, Derby 10.8
>
> Test (which fails):
>        ...{set fields, but not 'modified'}...
>        et = em.getTransaction();
>        et.begin();
>        em.persist(entity);
>        et.commit();
>        assertNotNull(entity.getModified());
>
> A query on the table, of course, shows a value for modified.
>
> Some things I've tried that haven't worked:
>      * Immediately after persist, entity.getModified();
>      * Immediately after persist, em.refresh(entity);
>
> On a possibly related note, I'm puzzled as to why I'm seeing the
> following message when I run my tests despite the fact that I'm running
> the enhancer on my domain classes via the openjpa-maven-plugin
> (codehaus):
>
>        INFO   [main] openjpa.Enhance - You have enabled runtime
>        enhancement, but have not specified the set of persistent
>        classes. ...
>
> I've inspected the .class file and it has a pcGetmodified among other
> things. So it looks like the classes are indeed getting enhanced.
>
> Any insights? Do I need a post processor to populate 'modified'?
>
>
>