Object persisting problem with @Manytoone - JPA/Hibernate

Asked

Viewed 1,778 times

3

I have the following problem: I can save/persist the two objects below, but JPA is not linking the ID of the DeclaracaoImportacao in the column ID class/entity .

Follows code

@Entity
@Table (name = "declaracaoimportacao")
public class DeclaracaoImportacao implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @Column(nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column
    private String importadorNome;
    private double freteTotalMoeda;
    private String importadorEnderecoMunicipio;
    private String importadorEnderecoLogradouro;
    private int importadorEnderecoCep;
    private String importadorEnderecoBairro;
    private int importadorEnderecoNumero;
    private String importadorEnderecoUf;
    private String conhecimentoCargaEmbarqueData;
    private String dataRegistro;
    private int freteMoedaNegociadaCodigo;  
    private int numeroDI;
    private double freteValorMoedaNegociada;
    private double freteCollect;
    private double fretePrepaid;
    private double freteTotalReais;


    @OneToMany(cascade={CascadeType.ALL},mappedBy = "declaracaoImportacao")
    @Fetch(FetchMode.JOIN)
    private List<Adicao> adicao  = new ArrayList<Adicao>();

    public DeclaracaoImportacao(){

    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<Adicao> getAdicoes() {
        return adicao;
    }

    public void setAdicao(ArrayList<Adicao> adicao) {
        this.adicao = adicao;
    }

    public void addAdicao(Adicao adicao) {
        addAdicao(adicao, true);
    }

    void addAdicao(Adicao adicao, boolean set) {
        if (adicao != null) {
            if(getAdicoes().contains(adicao)) {
                getAdicoes().set(getAdicoes().indexOf(adicao), adicao);
            }
            else {
                getAdicoes().add(adicao);
            }
            if (set) {
                adicao.setDi(this, false);              
            }
        }
    }
  // outros getters e setters

  @Override
    public boolean equals(Object object) {
        if (object == this)
            return true;
        if ((object == null) || !(object instanceof DeclaracaoImportacao))
            return false;

        final DeclaracaoImportacao di = (DeclaracaoImportacao)object;

        if (id != null && di.getId() != null) {
            return id.equals(di.getId());
        }
        return false;
    }
}

Following the class Adicao, that should receive the ID that comes from the class DeclaracaoImportacao:

@Entity
@Table(name = "adicao")
public class Adicao implements Serializable {   
    private static final long serialVersionUID = 1L;

    @Id
    @Column(nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id_adicao;

    @Column
    private String condicaoVendaIncoterm;
    private int paisOrigemMercadoriaCodigo;
    private String paisOrigemMercadoriaNome;    

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="id",referencedColumnName="id")
    private DeclaracaoImportacao declaracaoImportacao;  

    public Adicao(){

    }

    public Long getId() {
        return id_adicao;
    }
    public void setId(Long id) {
        this.id_adicao = id;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
    public DeclaracaoImportacao getDi() {
        return declaracaoImportacao;
    }
    public void setDi(DeclaracaoImportacao di) {
        setDi(di, true);
    }

    void setDi(DeclaracaoImportacao di, boolean add) {
        this.declaracaoImportacao = di;
        if (di != null && add) {
            di.addAdicao(this, false);
        }
    }
  // outros getters and setter

  @Override
     public boolean equals(Object object) {
        if (object == this)
            return true;
        if ((object == null) || !(object instanceof Adicao))
            return false;

        final Adicao adicao = (Adicao)object;

        if (id_adicao != null && adicao.getId() != null) {
            return id_adicao.equals(adicao.getId());
        }
        return false;
    }   

}

As you can see I’ve been quite concerned with maintaining the integrity of objects in the database.

Follow the DAO class to DeclaracaoImportacao:

public class DeclaracaoImportacaoFacade implements Serializable {

    private static final long serialVersionUID = 1L;

    DeclaracaoImportacaoDAO diDAO = new DeclaracaoImportacaoDAO();

    public void createDeclaracaoImportacao(DeclaracaoImportacao di){
        diDAO.beginTransaction();
      // Esse método save está dentro de uma superclasse DAO que faz a criação do EntityManager
        diDAO.save(di);
        diDAO.commitAndCloseTransaction();
    }

And that’s the class Dad GenericDAO:

abstract class GenericDAO<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("JSFCrudPU");
    private EntityManager em;

    private Class<T> entityClass;

    public void beginTransaction() {
        em = emf.createEntityManager();

        em.getTransaction().begin();
    }

    public void commit() {
        em.getTransaction().commit();
    }

    public void rollback() {
        em.getTransaction().rollback();
    }

    public void closeTransaction() {
        em.close();
    }

    public void commitAndCloseTransaction() {
        commit();
        closeTransaction();
    }

    public void flush() {
        em.flush();
    }

    public void joinTransaction() {
        em = emf.createEntityManager();
        em.joinTransaction();
    }

    public GenericDAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    public void save(T entity) {
        em.persist(entity);

    }

    public void delete(Object id, Class<T> classe) {
        T entityToBeRemoved = em.getReference(classe, id);

        em.remove(entityToBeRemoved);
    }

    public T update(T entity) {
        return em.merge(entity);
    }

    public T find(int entityID) {
        return em.find(entityClass, entityID);
    }

    public T findL(Long entityID) {
        return em.find(entityClass, entityID);
    }
}

When I will persist the entity DeclaracaoImportacao automatically it persists the class Adicao, or that you don’t need to call a save method(Adicao) for the addition class.

But, the JPA as I said earlier is failing to link the ID of the DeclaracaoImportacao on the table Adicao this causes the relation N->1 not to be created.

Follow prints showing the already persisted objects in Mysql.DeclaracaoImportacao persistido

Adicao: Adicao persistida

I really looked for everything personal, could give a strength ?

  • Welcome to Stack Overflow! Your question is very clear and very well described, good preparation!

1 answer

2


In JPA there is the concept of relationship owner (Relationship Owner). In your case it is the entity Item that holds a foreign key to the entity Declarationtax, therefore it is the entity Item that owns the relationship!

If you create a new addition and add it to the list of a declarationImportation, when saving the declaration the addition will also be saved, as you specified to do the cascade persist with the code below:

@OneToMany(cascade={CascadeType.ALL},mappedBy = "declaracaoImportacao")
@Fetch(FetchMode.JOIN)
private List<Adicao> adicao  = new ArrayList<Adicao>();

But the relationship has two sides! Then you should add the addition to the list of the declaration!

DeclaracaoImportacao declaracaoImportacao = new DeclaracaoImportacao();
Adicao adicao = new Adicao();

declaracaoImportacao.getAdicoes().add(adicao);  // Colocando a adicao na lista
adicao.setDi(declaracaoImportacao)             // Isso é importante!

diDAO.save(declaracaoImportacao);

Now yes the addition will be saved with the right id!

Summarizing how the class Addicao that owns the relationship is what makes the difference and not the class Declaracaoimportacao. As in the addition class its field declaredImportacao was null, Hibernate will save null in the database. If it were otherwise, that is, the addition class with the declared fieldImportation with the right and the declared classImportation with the empty list Hibernate would save everything correctly, because the declared classImportation does not own the relationship so it doesn’t even make a difference! But still it’s interesting to always make references consistent, so always add the two to each other.

  • Hello Sergio, thank you very much for the highly detailed reply I will try to implement these changes here. If it works already milestone as response !

  • Sergio, I have another problem, sometimes I will have more than one Addition, the tip you gave me only works when I have only one Addition. I am trying: for(int i =0; declaracImport.getAdicoes().size() <= i;i++ ){&#xA; adi = declaracImport.getAdicoes().get(i); &#xA; declaracImport.getAdicoes().add(adi); &#xA; adi.setDi(declaracImport);&#xA; } &#xA;diDAO.save(declaracaoImport; The only way it worked was: adi = declaracImport.getAdicoes().get(0); &#xA; declaracImport.getAdicoes().add(adi); &#xA; adi.setDi(declaracImport); Note that here I can only link the id of an Addition to a Statement

  • It works with as many additions as you want. You already have the addAdication(addition addition) method make it already add one object to the other. Something like: void addAdicao(Adicao adicao){ adicao.setDi(this); this.getAdicoes().add(adicao); } Hence always use this method when you want to add an addition. It may be interesting to make a copy of the addition inside the method and add the copy so as not to change the original.

  • Thanks Sergio , what worked was: DeclaracaoImportacao declaracaoImportacao = new DeclaracaoImportacao();&#xA;&#xA; Adicao adi = new Adicao();&#xA; &#xA; while (x < declaracaoImportacao.getAdicoes().size()){&#xA; &#xA; adi = declaracaoImportacao.getAdicoes().get(x);&#xA; declaracaoImportacao.addAdicao(adi);&#xA; x++;&#xA; &#xA; }&#xA;diDAO.save(declaracaoImportacao);

  • Oh yes, looking well now I think I had not understood your doubt of direct comment. If I can help in anything else just ask! :)

  • @Matheusmaciel this code is kind of weird, are you taking an addition from the list and adding it back to the list? I don’t know if this makes sense. It would not be something like this you want: for(int i = 0; i <= declaracImport.getAdicoes(). size(); i++ ){ Adi = declaracImport.getAdictions(). get(i); Adi.setDi(declaracImport); } diDAO.save(declaracaImport); ?

  • I did it, it was really weird that way !

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.