Bom dia a todos.
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.
As classes estão da seguinte forma:
@Entity
public class Imagem{
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String nome;
private String mime;
private Date data;
@Lob
private byte[] arquivo;
private Long length;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="idNoticia")
private Noticia noticia;
@Entity
public class Noticia {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String titulo;
private String conteudo;
private Date data;
@OneToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
@JoinColumn(name="idImagem")
private Imagem imagem;
@OneToMany(mappedBy = "noticia", cascade={CascadeType.ALL}, fetch=FetchType.LAZY)
private List<Comentario> comentarios;
@OneToMany(mappedBy = "noticia", cascade={CascadeType.ALL}, fetch=FetchType.LAZY)
private List<Imagem> imagens;
Obrigado desde já.
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…
cara,
vc tem dar um new na sua lista de Imagens.
t+
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:
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?
cara,
segue um exemplo ai, fiz o teste aqui e funcionou
@Entity
@Table(name="teste2")
public class Teste2 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer idteste2;
private String nome;
//bi-directional many-to-one association to Teste1
@OneToMany(mappedBy="teste2", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Teste1> teste1;
public Teste2() {
this.teste1 = new ArrayList<Teste1>();
}
}
@Entity
@Table(name="teste1")
public class Teste1 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int idteste1;
private String nome;
//bi-directional many-to-one association to Teste2
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="teste2")
private Teste2 teste2;
public Teste1() {
}
}
public class Teste {
public static void main(String[] args) {
EntityManager entityManager = Persistence.createEntityManagerFactory("PERSIST_UNIT").createEntityManager();
Teste2 t2 = new Teste2();
t2.setNome("t222");
Teste1 t11 = new Teste1();
t11.setNome("t112");
t11.setTeste2(t2);
t2.getTeste1().add(t11);
Teste1 t12 = new Teste1();
t12.setNome("t122");
t12.setTeste2(t2);
t2.getTeste1().add(t12);
Teste1 t13 = new Teste1();
t13.setNome("t132");
t13.setTeste2(t2);
t2.getTeste1().add(t13);
entityManager.getTransaction().begin();
entityManager.persist(t2);
entityManager.getTransaction().commit();
}
}
espero que te ajude,
t+
[quote=alissonvla]cara,
segue um exemplo ai, fiz o teste aqui e funcionou
@Entity
@Table(name="teste2")
public class Teste2 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer idteste2;
private String nome;
//bi-directional many-to-one association to Teste1
@OneToMany(mappedBy="teste2", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Teste1> teste1;
public Teste2() {
this.teste1 = new ArrayList<Teste1>();
}
}
@Entity
@Table(name="teste1")
public class Teste1 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int idteste1;
private String nome;
//bi-directional many-to-one association to Teste2
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="teste2")
private Teste2 teste2;
public Teste1() {
}
}
public class Teste {
public static void main(String[] args) {
EntityManager entityManager = Persistence.createEntityManagerFactory("PERSIST_UNIT").createEntityManager();
Teste2 t2 = new Teste2();
t2.setNome("t222");
Teste1 t11 = new Teste1();
t11.setNome("t112");
t11.setTeste2(t2);
t2.getTeste1().add(t11);
Teste1 t12 = new Teste1();
t12.setNome("t122");
t12.setTeste2(t2);
t2.getTeste1().add(t12);
Teste1 t13 = new Teste1();
t13.setNome("t132");
t13.setTeste2(t2);
t2.getTeste1().add(t13);
entityManager.getTransaction().begin();
entityManager.persist(t2);
entityManager.getTransaction().commit();
}
}
espero que te ajude,
t+[/quote]
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).
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.
Continua dando o mesmo erro quando eu seleciono a Imagem principal.
Atualmente está assim:
@Entity
public class Noticia implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String titulo;
private String conteudo;
private Date data;
@OneToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
@JoinColumn(name="idImagem", insertable=false, updatable=true)
private Imagem imagem;
@OneToMany(mappedBy = "noticia", cascade={CascadeType.ALL}, fetch=FetchType.LAZY)
private List<Comentario> comentarios;
@OneToMany(mappedBy = "noticia", cascade={CascadeType.ALL}, fetch=FetchType.LAZY, orphanRemoval=true)
private List<Imagem> imagens;
//gettes e setters
@Entity
public class Imagem implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String nome;
private String mime;
private Date data;
@Lob
private byte[] arquivo;
private Long length;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="idNoticia")
private Noticia noticia;
//getters e setters
cara,
tenta colocar isso no se JoinColumn
@JoinColumn(name = "CHAVE_ESTRAGEIRA", referencedColumnName = "CHAVE_PRIMARIA")
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:
if(getNoticia().getId() == null){
Imagem imagemPrincipal = getNoticia().getImagem();
getNoticia().setImagem(null);
noticiaDAO.salvar(getNoticia());
getNoticia().setImagem(imagemPrincipal);
noticiaDAO.atualizar(noticia);
}
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.
cara,
segue um exemplo que ilustra seu mapeamento e funcionou, segue
@Entity
@Table(name="teste2")
public class Teste2 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer idteste2;
private String nome;
//bi-directional many-to-one association to Teste1
@OneToMany(mappedBy="teste2", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Teste1> teste1s;
@JoinColumn(name = "teste1", referencedColumnName = "idteste1")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Teste1 teste1;
public Teste2() {
this.teste1s = new ArrayList<Teste1>();
}
}
@Entity
@Table(name="teste1")
public class Teste1 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int idteste1;
private String nome;
//bi-directional many-to-one association to Teste2
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="teste2")
private Teste2 teste2;
public Teste1() {
}
}
public class Teste {
public static void main(String[] args) {
EntityManager entityManager = Persistence.createEntityManagerFactory("PERSIST_UNIT").createEntityManager();
Teste1 t1 = new Teste1();
t1.setNome("t1");
Teste2 t2 = new Teste2();
t2.setNome("t222");
t2.setTeste1(t1);
Teste1 t11 = new Teste1();
t11.setNome("t112");
t11.setTeste2(t2);
t2.getTeste1s().add(t11);
Teste1 t12 = new Teste1();
t12.setNome("t122");
t12.setTeste2(t2);
t2.getTeste1s().add(t12);
Teste1 t13 = new Teste1();
t13.setNome("t132");
t13.setTeste2(t2);
t2.getTeste1s().add(t13);
entityManager.getTransaction().begin();
entityManager.persist(t2);
entityManager.getTransaction().commit();
}
}
t+
[quote=alissonvla]cara,
segue um exemplo que ilustra seu mapeamento e funcionou, segue
@Entity
@Table(name="teste2")
public class Teste2 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer idteste2;
private String nome;
//bi-directional many-to-one association to Teste1
@OneToMany(mappedBy="teste2", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Teste1> teste1s;
@JoinColumn(name = "teste1", referencedColumnName = "idteste1")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Teste1 teste1;
public Teste2() {
this.teste1s = new ArrayList<Teste1>();
}
}
@Entity
@Table(name="teste1")
public class Teste1 implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int idteste1;
private String nome;
//bi-directional many-to-one association to Teste2
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="teste2")
private Teste2 teste2;
public Teste1() {
}
}
public class Teste {
public static void main(String[] args) {
EntityManager entityManager = Persistence.createEntityManagerFactory("PERSIST_UNIT").createEntityManager();
Teste1 t1 = new Teste1();
t1.setNome("t1");
Teste2 t2 = new Teste2();
t2.setNome("t222");
t2.setTeste1(t1);
Teste1 t11 = new Teste1();
t11.setNome("t112");
t11.setTeste2(t2);
t2.getTeste1s().add(t11);
Teste1 t12 = new Teste1();
t12.setNome("t122");
t12.setTeste2(t2);
t2.getTeste1s().add(t12);
Teste1 t13 = new Teste1();
t13.setNome("t132");
t13.setTeste2(t2);
t2.getTeste1s().add(t13);
entityManager.getTransaction().begin();
entityManager.persist(t2);
entityManager.getTransaction().commit();
}
}
t+[/quote]
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.
já tentasse colocar no mapeamento da imagem principal o nullable como false?!