Insert em cascata [RESOLVIDO]

Estou tentando fazer um insert em cascata, ou seja, inserindo vários dados em várias tabelas através de relacionamento.
Por exemplo, tenho a classe A que tem um List da classe B.

O meu relacionamento está assim:

Classe A:

public class CLassA{

   @Id
   @Generated(GenerationTime.INSERT)
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Column(name="id_classA")
   private Long id;

   @OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
   @JoinColumn(name="id_classA", insertable=true, updatable=true)
   private List<ClassB> listClassB;

}

Classe B:

[code]
public class ClassB{
@Id
@Generated(GenerationTime.INSERT)
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name=“id_classB”, insertable=true, updatable=true)
private Long id;

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name=“id_classA”)
private ClassA classA;
}[/code]

Quando eu tento inserir uma ClassA com várias objetos da ClassB, dá erro.

    ArrayList<ClassB> list = new ArrayList<ClassB>();
    list.add(new ClassB());

    ClassA classA = new ClassA();
    classA.setListClassB(list);

    GenericDAO dao = new GenericDAO();
    dao.save(classA)

Só funciona quando eu faço ao contrário, ou seja, quando eu tento inserir uma ClassB com várias ClassA. Isso é erro de configuração? Ou não tem como fazer este insert?

Jedi_FeniX, sempre que você tiver algum problema e pedir um help, diga sempre qual foi o erro, ou pelo menos alguma mensagem que você puder.

E pelo que sei toda a classe para ser persistida precisa ter ID. Inclusive a annotation @Id são obrigatórios.

Seguinte…

Nesse tipo de relacionamento voce tem que ter um lado que manda no seu relacionamento.

No caso de relacionamentos @ManyToOne e @OneToMany o lado que tem o @ManyToOne é sempre o que manda na relacao, ou seja, o lado onde é realizado os inserts, deletes e o cascade funciona para as outras classes.

fica mais ou menos assim:

public class ClassB{  
    @ManyToOne(cascade={CascadeType.ALL})  
    @JoinColumn(name="id_classA")  
    private ClassA classA;  
}  

e sua ClassA fica assim:

public class CLassA{  
   
    @OneToMany(mappedBy="classA",cascade={CascadeType.ALL}, fetch=FetchType.EAGER)     
    private List<ClassB> listClassB; 
   
} 

onde esse “mappedBy” no @OneToMany indica que todo mapeamento necessário para seu relacionamento esta na outra classe.

Creio ser isso, se não entendi tudo errado. :wink: :wink: :wink: :wink: :wink:

Faça um teste, e quando der algum erro, por favor poste para nos.

[quote=otavio]Jedi_FeniX, sempre que você tiver algum problema e pedir um help, diga sempre qual foi o erro, ou pelo menos alguma mensagem que você puder.

E pelo que sei toda a classe para ser persistida precisa ter ID. Inclusive a annotation @Id são obrigatórios.[/quote]

ah sim,

estou partindo do principio que na classe dele já tenha o @Entity e o @Id que sao obrigatórios no caso de classes persistidas.

Xii, eu havia esquecido do mappedBy.

As outras anotações já existem, não coloquei para o post ficar menor.
O erro continua dando.

Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [test.ClassB]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:40)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2163)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2643)
        at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:51)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
        at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
        at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
        at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
        at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
        at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:334)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
        at daoGenericDAO.save(GenericDAO.java:76)
        at test.TestClassA.main(TestClassA.java:44)
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "id_classA" violates not-null constraint
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1592)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1327)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:192)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
        at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:33)
        ... 35 more

esse erro ja é outra coisa…

esse erro é pq no banco voce colocou que o ID é not null e voce esta inserindo null.

Veja na linha 40 do seu post

“Caused by: org.postgresql.util.PSQLException: ERROR: null value in column “id_classA” violates not-null constraint”

Para solucionar isso ou voce seta o ID na mao, cria uma sequence no banco (se suportar) e mapeia a sequence no seu id ou usa gerador automatico de IDs no seu mapeamento.

Olhei por cima nesse link e acho que é o que tu precisa (caso ainda nao tenha),

checa ai

http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e2167

[quote=Jedi_FeniX]As outras anotações já existem, não coloquei para o post ficar menor.
O erro continua dando.

Exception in thread "main" org.hibernate.exception.ConstraintViolationException: could not insert: [test.ClassB]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
        at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:40)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2163)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2643)
        at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:51)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
        at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
        at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
        at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
        at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
        at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:334)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
        at daoGenericDAO.save(GenericDAO.java:76)
        at test.TestClassA.main(TestClassA.java:44)
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "id_classA" violates not-null constraint
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1592)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1327)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:192)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
        at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:33)
        ... 35 more

Não tinha colocado o erro poque achei que estivesse claro, foi mal :wink:

pera ai,

esse erro ta ocorrendo depois que voce colocou o mapeamento que passei acima ne?

ja coloco o sequence no banco ou o generator no codigo? ou ja setou manualmente o id ?

Este erro é o mesmo que estava dando antes, com ou sem “mappedBy” dá este erro.
E sim já tem genereator.
Atualizei as classes com as outras anotações.

Os sqls que são gerados são esses:

Hibernate: insert into public.classA(name, status) values (?, ?)
Hibernate: select currval('public.id_classA_seq')
Hibernate: insert into public.classB (id_classA, name, status) values (?, ?, ?)

como voce ta preenchendo sua classe? tem como postar aqui?

e as classes com os generators tb…

Lembre-se que na sua classe B, você tem que inserir a instancia da classe A.

ClasseA classeA = new ClasseA();
List&lt;ClasseB&gt; listaClasseB = new ArrayList&lt;ClasseB&gt;();
ClasseB classeB = new ClasseB();
classeB.setClasseA(classeA); //aqui é o ponto
listaClasseB.add(classeB);
...
...
classeA.setListaClasseB(listaClasseB);
session.save(classeA);

[quote=Jair Rillo Junior]Lembre-se que na sua classe B, você tem que inserir a instancia da classe A.

ClasseA classeA = new ClasseA(); List&lt;ClasseB&gt; listaClasseB = new ArrayList&lt;ClasseB&gt;(); ClasseB classeB = new ClasseB(); classeB.setClasseA(classeA); //aqui é o ponto listaClasseB.add(classeB); ... ... classeA.setListaClasseB(listaClasseB); session.save(classeA); [/quote]

é isso que to tentando ver se ele ta fazendo.

:wink: :wink: :wink: :wink: :wink:

e se ele ta com o generator no id das duas classes …

Funcionou quando eu inclui o objeto da ClassA na ClassB. Achei meio estranha esta solução. Mas valeu pela a ajuda!!! :smiley:

Não é estranho, é como o pdioniziofilho disse

Ou seja, o lado da ClasseB que manda no relacionamento, portanto ela deve conhecer o objeto da ClasseA. Uma solução para evitar isso seria utilizar o relacionamento OneToMany unidirecional (que apenas a Classe A enxerga a classe B), porém isso dai iria mudar o seu schema (e talvez no seus requisitos isso não seja válido).

vc tem que inserir o objeto da classeA dentro da classeB e a classeB na lista da classeA, senao nao funciona.

Um tem que “ligar” com o outro ja que voce esta usando o mapeamento bidirecional

@Apenas complementando com o que o Jair disse.

Entendi.
Então para que server o “mappedBy”, se preciso incluir uma classe na outra?
E como ficaria a anotação com o relacionamento OneToMany unidirecional?

No caso do relacionamento unidirecional, irá ocorrer o seguinte:

  • Não existirá o atributo ClasseA dentro da ClasseB
  • Consequentemente, não havera o campo (CLASSEA_ID) na tabela CLASSEB (no banco de dados)
  • Haverá uma nova tabela (CLASSEA_CLASSEB) com 2 campos: IDs de ambas as tabelas.
  • Nesse caso não precisa do mappedBy.

Com o @OneToMany voce nao teria nada na sua classe que permitiria uma navegacao de volta para a classe que manda na relacao.

Exemplo:

public class ClassB{    
     @ManyToOne(cascade={CascadeType.ALL})    
     @JoinColumn(name="id_classA")    
     private ClassA classA;    
}    

removeria essse atributo classA da sua classe …

e teria que mudar seu banco, criando uma “JoinTable”

o mappedBy serve para dizer para sua classe que todo mapeamento necessario para a relacao esta na outra classe, e que quem manda na relacao é a outra classe.