2
@Entity
public class Auction{
    @ManyToOne(cascade=CascadeType.MERGE)
    private Member seller;

    @OneToOne(cascade=CascadeType.PERSIST)
    private Question question;
}

@Entity
public class Member{

}

@Entity
public class Question{
    @ManyToOne(cascade=CascadeType.MERGE)
    private Member personAsking;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
}



em.persist(auction);

How do I persist member if it doesn't exist, otherwise merge (update) it?

Tim
  • 514
  • 8
  • 17

2 Answers2

2

Add to your Auction.seller field CascadeType.PERSIST. Like this:

@Entity
public class Auction{
    @ManyToOne(cascade={CascadeType.MERGE, CascadeType.PERSIST})
    private Member seller;

    .....
}
V G
  • 18,822
  • 6
  • 51
  • 89
  • 1
    I get a duplicate primary key error on the seller's id when I do this and try to persist another Auction class that references the same seller. (I.e. the seller already exists in the database). – Tim Mar 08 '14 at 09:27
  • MySQL. The id field is an int (db = int(11)) and is not generated, as it is already unique for each member. – Tim Mar 08 '14 at 19:26
  • Persist cause an exception if the entity exists. You need to use merge. – Chris Mar 09 '14 at 02:17
0

Use CascadeType.merge, and use EntityManager.merge(). Merge will check if the entity is new or not and insert or update appropriately, and the cascade operation will work on referenced entities in the same way.

Chris
  • 20,138
  • 2
  • 29
  • 43
  • Is this the standard way? I did do this, but whenever I merge() an auction that already exists in the db (say to update some fields), it creates a new Question row in the database and orphans the old one. I think this is because the id for Question is auto generated. – Tim Mar 09 '14 at 02:52
  • Merge makes a copy that is managed and will have the IDs set after a flush or commit. So if you are going to reuse the auction and merge it later, you should keep the one returned from the em.merge call. Otherwise, calling merge on the old instance will have JPA find the question with no id set, and so insert it as if it was new. – Chris Mar 10 '14 at 00:12
  • Okay, I think I'm understanding. The first and second time we merge may be a month apart - we obviously don't keep a reference to the returned one. Another website changes the auction during this time. Is there a way to get around this issue? – Tim Mar 10 '14 at 01:14
  • I don't understand then. If there is a long time apart and the entity isn't held, it must be read in through the EntityManager somehow and so have correct references and IDs set. If you are having a specific problem with cascade merge, you should create a new question detailing what you are doing and what is happening. – Chris Mar 10 '14 at 13:47
  • Ahhhh I think I have just worked it out - calling merge(auction) the second time will merge the auction but create a new Question row in the database because the entity manager can't tell that the Question object in the later version of the Auction is the same as what is in the database (as ID is autogenerated). So just creates a new one. – Tim Mar 10 '14 at 20:54
  • As you said, the question should be about merge() not working as I thought it would. So, thank you very much for your help! I'll choose this as the correct answer as it technically is for the question I asked so may be helpful for future googlers. – Tim Mar 10 '14 at 20:54