Problem persisting object with @ManyToOne - JPA / Hibernate

3

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

Follow the 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 , which should receive the ID that comes from 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 was very concerned about maintaining the integrity of objects in the database.

Follow the DAO class for 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 this is the parent class 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 persist the DeclaracaoImportacao entity automatically it persists the Adicao class, ie I do not need to call a save method ( Adicao ) for the addition class.

But, JPA like I said before is no longer binding the ID of DeclaracaoImportacao in the Adicao table, this causes the N > 1 relation to not be created.

Here are some screenshots showing the persistent objects in MySQL.

Adicao :

I really looked for everything personal, could you give a force?

    
asked by anonymous 22.09.2016 / 21:12

1 answer

2

In JPA there is the concept of relationship owner. In your case it is the Add entity that has a foreign key for the entity DeclaracaoImportacao, therefore it is the entity Addiction that owns the relationship!

If you create a new addition and add it to the list of an import statement, saving the declaration to the addition will also be saved, as you specified to make the cascade persist with the following code:

@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 in the list of the declarationImport and also add the declarationImportation in the addition!

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 the addition will be saved with the right id!

Summarizing how the Addiction class that owns the relationship is the one that makes the difference and not the class DeclaracaoImportacao. As in the add class its field declarationImport was null, hibernate will save null in the database. If it was otherwise, that is, the class added with the declaration fieldImport with the right and class declarationImport with the empty list hibernate would save everything correctly, because the class declarationImportation does not own the relationship so it does not even matter! But even so it is always interesting to leave the references consistent, so always add the two to each other.

    
23.09.2016 / 13:51