[ESCLARECIDO] - Dúvida JPA: 1-N e N-1

Boa tarde pessoal!
Seguinte, em um mapeamento 1-N e N-1 eu crio um objeto X e atribuo a ele uma lista de novos objetos Y. neste momento nem X nem Y estão atachados. Ex:

X x = new X();
x.setNome( "XPTO" );
x.setListaDeY( this.retornaUmaListaDeY() );
// aqui manda salvar
meuDaoJpa.save( x );

Logo em seguida, ao tentar imprimir para cada Y o nome de X relacionado como abaixo,

for ( Y y : x.getListDeY ) {
                                 // Aqui dá NPE
  System.out.println( y.getX.getNome() );
}

está dando NPE. O que está errado?

Abaixo o mapeamento entre X e Y.

class X {
  ...
  @OneToMany(mappedBy = "x", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  private Set<Y> ys;
}

class Y {
    ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CD_X")
    private X x;
}

Experimenta executar um FLUSH na sessão, isso vai fazer com que a persistencia seja efetivada de fato. Inclusive deixe configurado para ele mostrar os sqls que estão sendo gerados para vc ver o que o ORM está fazendo.

flws

Olá fantomas.
fazendo o que você falou continua dando NPE.
Não sei se adianta mas eu estou utilizando Spring (JpaTemplate).
No método save do meu DAO eu adicionei o flush mas ainda dá NPE.
Méu método:

@Override
public T create(T obj) {
	this.getJpaTemplate().persist(obj);
        // Adicionei esta linha aqui
	this.getJpaTemplate().flush();
	return obj;
}

Quando eu seto x a cada y antes de atribuir a lista de y a x funciona direito mas eu acho que não era para ser necessário fazer isto para funcionar.
Tipo:
para cada y eu atribuo x e depois seto a lista de y em x. :roll:

Entendeu???..

Entendi…

A princípio também acho que deveria estar funcionando, como não vejo nada de muito óbvio no teu código…complicou. Mas mesmo assim vou dar dois chutes:

  1. Você já deu uma olhada nos atributos da anotação @ManyToOne? Aqueles insertable, updatable etc…

  2. No seu código vc apresentou o método x.setListaDeY( this.retornaUmaListaDeY() );, como é a implementação dele?
    Se for igual a isto listaDeYs = variosYs; experimente trocar para uma implementação que adicione item a item (y a y) na lista. Isto porque a JPA / Hibernate troca o objeto do tipo lista para um tipo de lista dele dinamicamente ao gerar a instancia do objeto, talvez quando vc atribui diretamente uma instancia de outra lista que certamente não é do tipo que ele espera vc esteja “confundindo” os algoritimos dele. Faça um teste e analise com o debugger.

flws

fantomas, acho que a implementação do retornaUmaListaDeY() já está do jeito que você sugeriu. Segue:

protected Set<Y> getYs(  ) {
		Set<Y> ys = new HashSet<Y>();		
		for ( int x = 0; x < 12; x ++ ) {
			Y y = new Y();
		        y.setName( "ABCD" );
			ys.add(y);
		}
		return ys;
	}

Agora se eu passar X e setar na lista de ys funciona. Segue:

protected Set<Y> getYs( X x ) {
	Set<Y> ys = new HashSet<Y>();		
	for ( int x = 0; x < 12; x ++ ) {
		Y y = new Y();
	        y.setName( "ABCD" );
                // Assim funciona mas não acho certo
                y.setX( x );
	        ys.add(y);
	}
		return ys;
	}

vc não pode simplismente criar um Y, e adciona a lista de X … vc tem que dizer a Y na relação de N-1 a referencia de X …

sendo assim

X x = new X(); x.setNome( &quot;XPTO&quot; ); x.setListaDeY( this.retornaUmaListaDeY() ); // aqui manda salvar meuDaoJpa.save( x );

o método setListaDeY teria que ser algo como

public void setListaDeY( Collection&lt;Y&gt; ys); this.listaDeY = ys; for (Y y : ys) y.setX(this); // &lt;== vc precisa avisar a Y, sobre sua ligação com X }

ou vc faz nesse ponto, ou faz no momento que vai crair X …

eu particularmente não gosto de usar setListaDeY… eu uso métodos como

public void addY(Y y) { this.getYs().add(y); y.setX(this); }

Entendi Lavieri.
Então o que eue achava que não era o correto é o correto.
Para cada y eu tenho que setar x e depois setar para x cada y correspondente.

Obrigado pessoal!!!