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;
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?
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.
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.
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 é 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),
[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
Lembre-se que na sua classe B, você tem que inserir a instancia da classe A.
ClasseA classeA = new ClasseA();
List<ClasseB> listaClasseB = new ArrayList<ClasseB>();
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<ClasseB> listaClasseB = new ArrayList<ClasseB>();
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.
e se ele ta com o generator no id das duas classes …
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).
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?
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.