0
votes

When I have an Entity with relationships I don't know which is the best way to save changes to DB.

Here is a simplified entity. Please consider I have made little changes to the code to post it here and I can have introduced some errors.

public class Permessitemporanei implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "ID_permesso")
    private Integer iDpermesso;
    @Column(name = "Stato_permesso")
    private Integer statopermesso;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "iDpermesso")
    private Collection<Accessiconpermesso> accessiconpermessoCollection;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "iDpermesso")
    private Ingressiconpermesso  ingressiconpermesso;

As you can see it is linked to other 2 entities with a OneToMany and OneToOne relationships. I'm using Glassfish with jta so transactions and entityManagers are managed by the container.

At a time I have a detached (JPA terminology) Permessitemporanei instance in memory. I have to persist the following changes to the database: 1- the associated ingressiconpermesso must be deleted 2- a new ingressiconpermesso must be created 3- statopermesso field must be updated 4- a new Accessiconpermesso must be added to the collection accessiconpermessoCollection

Which is the best way of doing so ? Perhaps I can do all necessary changes in the Permessitemporanei instance an merge it but I had many troubles doing so and start to think it is not the right side of the relationships to persist changes. For me it more natural to save an object at a time, so eliminating all those cascade = CascadeType.ALL.

Suppose my Permessitemporanei instance is called 'permesso' ; my code is something like this:

  1. getEntityManager().remove(permesso.ingressiconpermesso);
  2. getEntityManager().persist(a new Ingressiconpermesso );
  3. getEntityManager().merge(permesso) // once its statopermesso field has been updated;
  4. getEntityManager().perist(a new Accessiconpermesso );

Obviously this way I have to manually update the in memory 'permesso' with all the changes I made on Database.

Is there a better approach ?

By the way all the JPA relationships I have seen are bidirectional. Can I make them unidirectional ? To put it in other words can I safely eliminate Code:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "iDpermesso") private Collection accessiconpermessoCollection;

from the Permessitemporanei entity preserving it on the Accessiconpermesso entity or do i break JPA ?

Thanks Filippo

1

1 Answers

3
votes

The way I like to approach complex entity updates is to:

  1. Start a new transaction.
  2. Make all the changes that I want to make against my Objects in memory.
  3. Tell the EntityManager what I did once I'm done.
  4. Commit the transaction.

But first things first, you will likely have a much easier time of things if you get a non-detached Permessitemporanei instance to start with:

Permessitemporanei persistentInstance = em.find(Permessitemporanei.class, detachedInstance.getId());

Then do all of your changes in memory, inform the EntityManager, and commit the transaction:

//begin a transaction
em.getTransaction().begin();

//remember the old Ingressiconpermesso instance
Ingressiconpermesso oldIngression = persistentInstance.getIngressiconpermesso();

//create a new Ingressiconpermesso instance
Ingressiconpermesso newIngression = new Ingressiconpermesso();
//call newIngression.set...() methods here

//associate the new Ingressiconpermesso with the Permessitemporanei 
persistentInstance.setIngressiconpermesso(newIngression);

//update statopermesso
persistentInstance.setStatopermesso(7); //replace '7' with whatever the real value is

//add a new Accessiconpermesso
Accessiconpermesso accession = new Accessiconpermesso();
//call accession.set...() methods here

//associate the Accessiconpermesso with the Permessitemporanei
accession.setPermissitemporanei(persistentInstance);

//now tell the EntityManager what we did
em.remove(oldIngression);        //delete the old Ingressiconpermesso 
em.persist(newIngression);       //add the new Ingressiconpermesso 
em.persist(accession);           //add the Accessiconpermesso
em.merge(persistentInstance);    //update the Permessitemporanei

//commit the transaction
em.getTransaction().commit();

To answer your other question, no, you generally do not need to annotate both sides of a relationship. You can remove your @OneToMany annotation if you want, and it shouldn't break anything (as far as JPA cares, anyways...you may well have application code that relies upon this Collection being present and properly populated, and removing the JPA mapping will of course break any such code). However, I don't really think you gain anything by removing it, so I'd recommend leaving it alone.