Estou com o seguinte problema: tenho uma classe Noticia que tem um relacionamento OneToMany com Imagem (que por sua vez tem um relacionamento ManyToOne com Noticia). Basicamente, na tabela Imagem tem uma foreign key para noticia (sob a coluna idNoticia). Quando eu mando salvar a Noticia (sendo que tem Cascade), ele tenta salvar a Imagem primeiro! Mas, se ele tentar salvar a Imagem primeiro, ele terá uma constraint violation, porque idNoticia não pode ser null.
bom coloca o annotation joinColumn em noticias a baixo do oneToMany e adiciona a propriedade dele nullable com false, vê ai se dá certo, já fiz alguns testes antes em algumas aplicações minhas e ele invertia a ordem em que adicionava os itens ou colocava um valor 0 na foreign key depois editava para o valor certo…
A
alissonvla
cara,
vc tem dar um new na sua lista de Imagens.
t+
F
fernando.camargo
A lista de imagens está carregada corretamente com as imagens e cada imagem está com a propriedade ‘noticia’ setada para a Noticia. Esse não é o problema.
E… tentei o que você disse, porém recebi esse erro:
F
fernando.camargo
Tentei colocar o ‘nullable=false’ no @JoinColumn da Imagem e obtive esse erro:
Como pode dizer que Noticia é transient se está anotado normalmente? E quando eu salvo uma Noticia sem nenhuma imagem, funciona normalmente.
Uma dúvida que eu tenho… é necessário implementar Serializable para funcionar?
A
alissonvla
cara,
segue um exemplo ai, fiz o teste aqui e funcionou
@Entity@Table(name="teste2")publicclassTeste2implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateIntegeridteste2;privateStringnome;//bi-directional many-to-one association to Teste1@OneToMany(mappedBy="teste2",orphanRemoval=true,cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateList<Teste1>teste1;publicTeste2(){this.teste1=newArrayList<Teste1>();}}
@Entity@Table(name="teste1")publicclassTeste1implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateintidteste1;privateStringnome;//bi-directional many-to-one association to Teste2@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="teste2")privateTeste2teste2;publicTeste1(){}}
@Entity@Table(name="teste2")publicclassTeste2implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateIntegeridteste2;privateStringnome;//bi-directional many-to-one association to Teste1@OneToMany(mappedBy="teste2",orphanRemoval=true,cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateList<Teste1>teste1;publicTeste2(){this.teste1=newArrayList<Teste1>();}}
@Entity@Table(name="teste1")publicclassTeste1implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateintidteste1;privateStringnome;//bi-directional many-to-one association to Teste2@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="teste2")privateTeste2teste2;publicTeste1(){}}
Obrigado pela ajuda. O que vi de diferente no que você fez foi colocar o Serializable. Coloquei aqui também e não deu erro. Porém, quando vou olhar no banco de dados, ele não inseriu nada.
E agora eu entendi porque ele tentava inserir a Imagem primeiro. Porque tenho um campo de Imagem na Noticia que define qual a imagem principal da Noticia. Então, para salvar a Noticia, ele tenta primeiro salvar a Imagem principal dela, sendo que essa requer o id da Noticia. Há alguma forma de informar o Hibernate para que salve esse campo em um update, ao invés de um insert?
Enquanto isso vo tentar entender o que aconteceu. O Hibernate imprimiu as queries, mas não salvou nada no banco (isso sem eu escolher a Imagem principal).
F
fernando.camargo
Achei na documentação do Hibernate a propriedade ‘insertable’ de @JoinColumn. Coloquei ela false e ‘updateable’ true. Creio que isso resolva o problema da imagem principal. Vou testar aqui.
F
fernando.camargo
Continua dando o mesmo erro quando eu seleciono a Imagem principal.
Atualmente está assim:
@EntitypublicclassNoticiaimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.AUTO)privateLongid;privateStringtitulo;privateStringconteudo;privateDatedata;@OneToOne(fetch=FetchType.LAZY,cascade={CascadeType.ALL})@JoinColumn(name="idImagem",insertable=false,updatable=true)privateImagemimagem;@OneToMany(mappedBy="noticia",cascade={CascadeType.ALL},fetch=FetchType.LAZY)privateList<Comentario>comentarios;@OneToMany(mappedBy="noticia",cascade={CascadeType.ALL},fetch=FetchType.LAZY,orphanRemoval=true)privateList<Imagem>imagens;//gettes e setters
@EntitypublicclassImagemimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.AUTO)privateLongid;privateStringnome;privateStringmime;privateDatedata;@Lobprivatebyte[]arquivo;privateLonglength;@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="idNoticia")privateNoticianoticia;//getters e setters
Bem… eu queria alguma Annotation para fazer isso… mas como não achei nenhuma, tive que fazer gambiarra mesmo.
No meu botão salvar estou fazendo o seguinte:
Quando for uma Noticia nova, eu armazeno a Imagem principal em uma variável temporaria, seto a Imagem principal da Noticia para null, salvo e depois adiciono a Imagem principal e atualizo.
Se alguem souber alguma anotação que faça isso para mim, postem aqui, por favor. Vou esperar mais um tempo antes de marcar como [RESOLVIDO].
Obrigado a todos pela ajuda.
A
alissonvla
cara,
segue um exemplo que ilustra seu mapeamento e funcionou, segue
@Entity@Table(name="teste2")publicclassTeste2implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateIntegeridteste2;privateStringnome;//bi-directional many-to-one association to Teste1@OneToMany(mappedBy="teste2",orphanRemoval=true,cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateList<Teste1>teste1s;@JoinColumn(name="teste1",referencedColumnName="idteste1")@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)privateTeste1teste1;publicTeste2(){this.teste1s=newArrayList<Teste1>();}}
@Entity@Table(name="teste1")publicclassTeste1implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateintidteste1;privateStringnome;//bi-directional many-to-one association to Teste2@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="teste2")privateTeste2teste2;publicTeste1(){}}
segue um exemplo que ilustra seu mapeamento e funcionou, segue
@Entity@Table(name="teste2")publicclassTeste2implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateIntegeridteste2;privateStringnome;//bi-directional many-to-one association to Teste1@OneToMany(mappedBy="teste2",orphanRemoval=true,cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateList<Teste1>teste1s;@JoinColumn(name="teste1",referencedColumnName="idteste1")@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)privateTeste1teste1;publicTeste2(){this.teste1s=newArrayList<Teste1>();}}
@Entity@Table(name="teste1")publicclassTeste1implementsSerializable{privatestaticfinallongserialVersionUID=1L;@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateintidteste1;privateStringnome;//bi-directional many-to-one association to Teste2@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="teste2")privateTeste2teste2;publicTeste1(){}}
Agora já está tudo funcionando. Quanto a não salvar, o problema estava no commit. Eu estava usando one-session-per-view, passando a Session do Hibernate na requestScope no restoreView e dando commit no renderResponse. Mas, há um redirecionamento de página, então perdia a Session do Hibernate. Fiz alguns ajustes e funcionou normal.
E, como eu disse, eu fiz aquela ‘gambiarra’ de setar para null a Imagem principal da Noticia, salvar a Noticia e depois setar a Imagem principal e dar um update. Tive que fazer isso manualmente. A única coisa que eu queria, caso possível, era que o Hibernate gerenciasse isso para mim.
CharlesAlves
já tentasse colocar no mapeamento da imagem principal o nullable como false?!