EJB - retrieving the entity you've just persisted (with autogenerated key)

Discussion in 'Java' started by ses, Feb 24, 2011.

  1. ses

    ses Guest

    I assume this must be a fairly common task but I'm struggling to find
    the best way to achieve this.

    How do you best retrieve the entity you've just persisted with
    entityManager.persist(myEntity), so that you can then use it in the
    next part of a transaction.

    I'm referring to an entity for which the container or database manages
    a generated primary key. Therefore you want to retrieve what you've
    just persisted so that you can for example establish another
    relationship - e.g. anotherEntity.add(myEntity) then
    entityManager.merge(anotherEntity).

    I am trying to do this in a session bean method and carry it out all
    as one transaction. The way I am retrieving myEntity after persisting
    is simply selecting the entity with the highest key value (is simple
    auto increment in MySQL) but there is some problem with this. It
    retrieves the entity fine with its newly generated key, however when I
    try to merge it or merge another entity with which I establish a
    relationship to myEntity I get the following exception:

    "null primary key encountered in unit of work"

    Any help would be much appreciated, I'm really asking if there is a
    better way to do this (persist-find-merge in a transactional EJB
    session bean method doesn't seem to be a good pattern, or at least
    doesn't seem to be working for me!)
     
    ses, Feb 24, 2011
    #1
    1. Advertising

  2. On 24/02/2011 15:11, ses allegedly wrote:
    > I assume this must be a fairly common task but I'm struggling to find
    > the best way to achieve this.
    >
    > How do you best retrieve the entity you've just persisted with
    > entityManager.persist(myEntity), so that you can then use it in the
    > next part of a transaction.
    >
    > I'm referring to an entity for which the container or database manages
    > a generated primary key. Therefore you want to retrieve what you've
    > just persisted so that you can for example establish another
    > relationship - e.g. anotherEntity.add(myEntity) then
    > entityManager.merge(anotherEntity).
    >
    > I am trying to do this in a session bean method and carry it out all
    > as one transaction. The way I am retrieving myEntity after persisting
    > is simply selecting the entity with the highest key value (is simple
    > auto increment in MySQL) but there is some problem with this. It
    > retrieves the entity fine with its newly generated key, however when I
    > try to merge it or merge another entity with which I establish a
    > relationship to myEntity I get the following exception:
    >
    > "null primary key encountered in unit of work"
    >
    > Any help would be much appreciated, I'm really asking if there is a
    > better way to do this (persist-find-merge in a transactional EJB
    > session bean method doesn't seem to be a good pattern, or at least
    > doesn't seem to be working for me!)


    Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    this -- and then work on the returned instance.

    HTH,

    --
    DF.
     
    Daniele Futtorovic, Feb 24, 2011
    #2
    1. Advertising

  3. ses

    ses Guest

    On Feb 24, 6:35 pm, Daniele Futtorovic <da.futt.n...@laposte-dot-
    net.invalid> wrote:
    > On 24/02/2011 15:11, ses allegedly wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > I assume this must be a fairly common task but I'm struggling to find
    > > the best way to achieve this.

    >
    > > How do you best retrieve the entity you've just persisted with
    > > entityManager.persist(myEntity), so that you can then use it in the
    > > next part of a transaction.

    >
    > > I'm referring to an entity for which the container or database manages
    > > a generated primary key. Therefore you want to retrieve what you've
    > > just persisted so that you can for example establish another
    > > relationship - e.g. anotherEntity.add(myEntity) then
    > > entityManager.merge(anotherEntity).

    >
    > > I am trying to do this in a session bean method and carry it out all
    > > as one transaction. The way I am retrieving myEntity after persisting
    > > is simply selecting the entity with the highest key value (is simple
    > > auto increment in MySQL) but there is some problem with this. It
    > > retrieves the entity fine with its newly generated key, however when I
    > > try to merge it or merge another entity with which I establish a
    > > relationship to myEntity I get the following exception:

    >
    > > "null primary key encountered in unit of work"

    >
    > > Any help would be much appreciated, I'm really asking if there is a
    > > better way to do this (persist-find-merge in a transactional EJB
    > > session bean method doesn't seem to be a good pattern, or at least
    > > doesn't seem to be working for me!)

    >
    > Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    > this -- and then work on the returned instance.
    >
    > HTH,
    >
    > --
    > DF.


    I don't think you can merge in JPA before you've called persist, or do
    you mean call merge after persist?
     
    ses, Feb 24, 2011
    #3
  4. On 24/02/2011 19:40, ses allegedly wrote:
    > On Feb 24, 6:35 pm, Daniele Futtorovic<da.futt.n...@laposte-dot-
    >>
    >> Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    >> this -- and then work on the returned instance.
    >>
    >> HTH,
    >>

    > I don't think you can merge in JPA before you've called persist, or do
    > you mean call merge after persist?


    As I said, I have only a vague notion of the technology you're
    describing, but in Hibernate, the interface of which looks very similar
    to this EntityManager, I would use merge _instead of_ (the equivalent
    of) persist. #merge is supposed to persist if the entity does not yet
    exist, and update it if it does. Merging a 'blank' entity returns me a
    (copy of a) persisted entity with the newly assigned identifier set.

    --
    DF.
     
    Daniele Futtorovic, Feb 24, 2011
    #4
  5. ses

    Lew Guest

    ses wrote:
    > Daniele Futtorovic wrote:
    >> Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    >> this -- and then work on the returned instance.

    >
    > I don't think you can merge in JPA before you've called persist, or do
    > you mean call merge after persist?
    >


    Sure you can. I've done it many times and it's worked.

    There are subtleties of the semantics, but you can do it.

    --
    Lew
     
    Lew, Feb 24, 2011
    #5
  6. On 11-02-24 02:40 PM, ses wrote:
    > On Feb 24, 6:35 pm, Daniele Futtorovic<da.futt.n...@laposte-dot-
    > net.invalid> wrote:
    >> On 24/02/2011 15:11, ses allegedly wrote:
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>
    >>> I assume this must be a fairly common task but I'm struggling to find
    >>> the best way to achieve this.

    >>
    >>> How do you best retrieve the entity you've just persisted with
    >>> entityManager.persist(myEntity), so that you can then use it in the
    >>> next part of a transaction.

    >>
    >>> I'm referring to an entity for which the container or database manages
    >>> a generated primary key. Therefore you want to retrieve what you've
    >>> just persisted so that you can for example establish another
    >>> relationship - e.g. anotherEntity.add(myEntity) then
    >>> entityManager.merge(anotherEntity).

    >>
    >>> I am trying to do this in a session bean method and carry it out all
    >>> as one transaction. The way I am retrieving myEntity after persisting
    >>> is simply selecting the entity with the highest key value (is simple
    >>> auto increment in MySQL) but there is some problem with this. It
    >>> retrieves the entity fine with its newly generated key, however when I
    >>> try to merge it or merge another entity with which I establish a
    >>> relationship to myEntity I get the following exception:

    >>
    >>> "null primary key encountered in unit of work"

    >>
    >>> Any help would be much appreciated, I'm really asking if there is a
    >>> better way to do this (persist-find-merge in a transactional EJB
    >>> session bean method doesn't seem to be a good pattern, or at least
    >>> doesn't seem to be working for me!)

    >>
    >> Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    >> this -- and then work on the returned instance.
    >>
    >> HTH,
    >>
    >> --
    >> DF.

    >
    > I don't think you can merge in JPA before you've called persist, or do
    > you mean call merge after persist?


    For a good discussion, see
    http://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-detached-entities/.
    I particularly recommend "The Pattern" section at the bottom. I'd reword
    the second piece of advice as

    "When updating an existing *managed* entity, we do not invoke any
    EntityManager method; the JPA provider will automatically update the
    database at flush or commit time."

    This ties in better with the third guideline. Main point is, and this is
    something that practically all of us have done when starting out with
    JPA, you don't need to call merge() or persist() to "save" changes to a
    managed entity. That's one of the main reasons we've got the EntityManager.

    The persistence specifications (JSR 220 and/or JSR 317) are your
    authoritative references. They are very readable specs.

    I'm not sure I understand your specific problem. You're in the same
    transaction - there's no way in your code of passing the newly-persisted
    and now managed entity to the next spot that needs to do something with
    it? What I'm saying is, I don't get the "find" part of
    persist-find-merge...in fact I'm not even convinced you need the "merge"
    in your scenario.

    As an aside, it seems you're using IDENTITY as your ID generation
    strategy. Is that so?

    AHS

    --
    We must recognize the chief characteristic of the modern era - a
    permanent state of what I call violent peace.
    -- James D. Watkins
     
    Arved Sandstrom, Feb 24, 2011
    #6
  7. ses

    ses Guest

    On Feb 24, 10:06 pm, Arved Sandstrom <>
    wrote:
    > On 11-02-24 02:40 PM, ses wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On Feb 24, 6:35 pm, Daniele Futtorovic<da.futt.n...@laposte-dot-
    > > net.invalid>  wrote:
    > >> On 24/02/2011 15:11, ses allegedly wrote:

    >
    > >>> I assume this must be a fairly common task but I'm struggling to find
    > >>> the best way to achieve this.

    >
    > >>> How do you best retrieve the entity you've just persisted with
    > >>> entityManager.persist(myEntity), so that you can then use it in the
    > >>> next part of a transaction.

    >
    > >>> I'm referring to an entity for which the container or database manages
    > >>> a generated primary key. Therefore you want to retrieve what you've
    > >>> just persisted so that you can for example establish another
    > >>> relationship - e.g. anotherEntity.add(myEntity) then
    > >>> entityManager.merge(anotherEntity).

    >
    > >>> I am trying to do this in a session bean method and carry it out all
    > >>> as one transaction. The way I am retrieving myEntity after persisting
    > >>> is simply selecting the entity with the highest key value (is simple
    > >>> auto increment in MySQL) but there is some problem with this. It
    > >>> retrieves the entity fine with its newly generated key, however when I
    > >>> try to merge it or merge another entity with which I establish a
    > >>> relationship to myEntity I get the following exception:

    >
    > >>> "null primary key encountered in unit of work"

    >
    > >>> Any help would be much appreciated, I'm really asking if there is a
    > >>> better way to do this (persist-find-merge in a transactional EJB
    > >>> session bean method doesn't seem to be a good pattern, or at least
    > >>> doesn't seem to be working for me!)

    >
    > >> Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    > >> this -- and then work on the returned instance.

    >
    > >> HTH,

    >
    > >> --
    > >> DF.

    >
    > > I don't think you can merge in JPA before you've called persist, or do
    > > you mean call merge after persist?

    >
    > For a good discussion, seehttp://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-d....
    > I particularly recommend "The Pattern" section at the bottom. I'd reword
    > the second piece of advice as
    >
    > "When updating an existing *managed* entity, we do not invoke any
    > EntityManager method; the JPA provider will automatically update the
    > database at flush or commit time."
    >
    > This ties in better with the third guideline. Main point is, and this is
    > something that practically all of us have done when starting out with
    > JPA, you don't need to call merge() or persist() to "save" changes to a
    > managed entity. That's one of the main reasons we've got the EntityManager.
    >
    > The persistence specifications (JSR 220 and/or JSR 317) are your
    > authoritative references. They are very readable specs.
    >
    > I'm not sure I understand your specific problem. You're in the same
    > transaction - there's no way in your code of passing the newly-persisted
    > and now managed entity to the next spot that needs to do something with
    > it? What I'm saying is, I don't get the "find" part of
    > persist-find-merge...in fact I'm not even convinced you need the "merge"
    > in your scenario.
    >
    > As an aside, it seems you're using IDENTITY as your ID generation
    > strategy. Is that so?
    >
    > AHS
    >
    > --
    > We must recognize the chief characteristic of the modern era - a
    > permanent state of what I call violent peace.
    > -- James D. Watkins


    Thanks for that link, it is very useful. Because I'm using a detached
    entity I think merge will be suitable for what I need.

    In actual fact it is a relationship that is causing the error - I have
    a structure like this:

    User --> Location --> Booking

    Where --> depicts a one-to-many unidirectional relationship. I am
    trying to persist a new Location (which has zero Bookings), then add
    it to a User and merge the User. The problem is the relationship
    between Location and Booking - if I remove this relationship (the
    field and the get and set from the Location entity) then it works
    fine. But obviously I want this relationship to remain so I can in the
    future add bookings to the location.

    To reiterate, the exception is:

    "null primary key encountered in unit of work"

    I thought the problem was Location had a null primary key / id after
    persisting, but I've proved this not to be the case by logging the id
    and it seems clear to me now it is the Location --> Booking
    relationship that is the issue.
     
    ses, Feb 25, 2011
    #7
  8. ses

    ses Guest

    On Feb 25, 12:20 pm, ses <> wrote:
    > On Feb 24, 10:06 pm, Arved Sandstrom <>
    > wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On 11-02-24 02:40 PM, ses wrote:

    >
    > > > On Feb 24, 6:35 pm, Daniele Futtorovic<da.futt.n...@laposte-dot-
    > > > net.invalid>  wrote:
    > > >> On 24/02/2011 15:11, ses allegedly wrote:

    >
    > > >>> I assume this must be a fairly common task but I'm struggling to find
    > > >>> the best way to achieve this.

    >
    > > >>> How do you best retrieve the entity you've just persisted with
    > > >>> entityManager.persist(myEntity), so that you can then use it in the
    > > >>> next part of a transaction.

    >
    > > >>> I'm referring to an entity for which the container or database manages
    > > >>> a generated primary key. Therefore you want to retrieve what you've
    > > >>> just persisted so that you can for example establish another
    > > >>> relationship - e.g. anotherEntity.add(myEntity) then
    > > >>> entityManager.merge(anotherEntity).

    >
    > > >>> I am trying to do this in a session bean method and carry it out all
    > > >>> as one transaction. The way I am retrieving myEntity after persisting
    > > >>> is simply selecting the entity with the highest key value (is simple
    > > >>> auto increment in MySQL) but there is some problem with this. It
    > > >>> retrieves the entity fine with its newly generated key, however when I
    > > >>> try to merge it or merge another entity with which I establish a
    > > >>> relationship to myEntity I get the following exception:

    >
    > > >>> "null primary key encountered in unit of work"

    >
    > > >>> Any help would be much appreciated, I'm really asking if there is a
    > > >>> better way to do this (persist-find-merge in a transactional EJB
    > > >>> session bean method doesn't seem to be a good pattern, or at least
    > > >>> doesn't seem to be working for me!)

    >
    > > >> Not sure about EJB, but in pure Hibernate I'd use #merge(Object) for
    > > >> this -- and then work on the returned instance.

    >
    > > >> HTH,

    >
    > > >> --
    > > >> DF.

    >
    > > > I don't think you can merge in JPA before you've called persist, or do
    > > > you mean call merge after persist?

    >
    > > For a good discussion, seehttp://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-d....
    > > I particularly recommend "The Pattern" section at the bottom. I'd reword
    > > the second piece of advice as

    >
    > > "When updating an existing *managed* entity, we do not invoke any
    > > EntityManager method; the JPA provider will automatically update the
    > > database at flush or commit time."

    >
    > > This ties in better with the third guideline. Main point is, and this is
    > > something that practically all of us have done when starting out with
    > > JPA, you don't need to call merge() or persist() to "save" changes to a
    > > managed entity. That's one of the main reasons we've got the EntityManager.

    >
    > > The persistence specifications (JSR 220 and/or JSR 317) are your
    > > authoritative references. They are very readable specs.

    >
    > > I'm not sure I understand your specific problem. You're in the same
    > > transaction - there's no way in your code of passing the newly-persisted
    > > and now managed entity to the next spot that needs to do something with
    > > it? What I'm saying is, I don't get the "find" part of
    > > persist-find-merge...in fact I'm not even convinced you need the "merge"
    > > in your scenario.

    >
    > > As an aside, it seems you're using IDENTITY as your ID generation
    > > strategy. Is that so?

    >
    > > AHS

    >
    > > --
    > > We must recognize the chief characteristic of the modern era - a
    > > permanent state of what I call violent peace.
    > > -- James D. Watkins

    >
    > Thanks for that link, it is very useful. Because I'm using a detached
    > entity I think merge will be suitable for what I need.
    >
    > In actual fact it is a relationship that is causing the error - I have
    > a structure like this:
    >
    > User --> Location --> Booking
    >
    > Where --> depicts a one-to-many unidirectional relationship. I am
    > trying to persist a new Location (which has zero Bookings), then add
    > it to a User and merge the User. The problem is the relationship
    > between Location and Booking - if I remove this relationship (the
    > field and the get and set from the Location entity) then it works
    > fine. But obviously I want this relationship to remain so I can in the
    > future add bookings to the location.
    >
    > To reiterate, the exception is:
    >
    > "null primary key encountered in unit of work"
    >
    > I thought the problem was Location had a null primary key / id after
    > persisting, but I've proved this not to be the case by logging the id
    > and it seems clear to me now it is the Location --> Booking
    > relationship that is the issue.


    I think I have now resolved the issue, it was simply that I hadn't
    added the @GeneratedValue annotation to the id columns with
    @GeneratedValue(GenerationStrategy.IDENTITY)

    I didn't realise this was required in order for the persistence
    manager to retrieve the ID in the case that the database generates it
    (rather than the container).
     
    ses, Feb 25, 2011
    #8
  9. On 11-02-25 10:47 AM, ses wrote:
    [ SNIP ]

    > I think I have now resolved the issue, it was simply that I hadn't
    > added the @GeneratedValue annotation to the id columns with
    > @GeneratedValue(GenerationStrategy.IDENTITY)
    >
    > I didn't realise this was required in order for the persistence
    > manager to retrieve the ID in the case that the database generates it
    > (rather than the container).


    That's sort of why I asked whether you were using IDENTITY; I had my
    suspicions as soon as you mentioned "null primary key".

    http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequence_Strategies
    is a decent discussion. You'll note upon reading here, that if you're
    using IDENTITY it has some things to look out for, one of them being
    that you won't have an ID until after you flush or commit.

    Not having a @GeneratedValue at all is OK, which is what you started out
    with. One app I help maintain has a few audit-type entities set up this
    way; the @Id values are GUIDs created in a @PrePersist method. One way
    or the other, either by the application or by a @GeneratedValue, you
    obviously have to set (or have set) the ID somehow.

    AHS
    --
    We must recognize the chief characteristic of the modern era - a
    permanent state of what I call violent peace.
    -- James D. Watkins
     
    Arved Sandstrom, Feb 25, 2011
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. gk
    Replies:
    1
    Views:
    393
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=
    Aug 11, 2006
  2. Daniel Pitts
    Replies:
    0
    Views:
    340
    Daniel Pitts
    Nov 14, 2007
  3. markla
    Replies:
    1
    Views:
    584
    Steven Cheng
    Oct 6, 2008
  4. ThatsIT.net.au

    Entity, problem with entity key

    ThatsIT.net.au, Sep 6, 2009, in forum: ASP .Net
    Replies:
    1
    Views:
    1,247
    ThatsIT.net.au
    Sep 7, 2009
  5. Raymond Schanks
    Replies:
    0
    Views:
    702
    Raymond Schanks
    Aug 3, 2010
Loading...

Share This Page