Como salvar objeto de um campo digitado em um relacionamento m2m?

2 respostas
S

Obs: utilizo JSF + Hibernate (Jboss Seam).

Pessoal, na minha aplicação tenho a classe Operador que pode receber um ou muitos telefones, e esses telefones são digitados na hora de cadastrar um operador.

Qual a maneira mais correta de fazer isso?

Eu já utilizei m2m em outras áreas, mas eu não digitava nenhum valor e sim escolhia através de checkboxes, e isso é tranquilo.

Alguém com paciencia veja como estou tentando fazer:

Na classe de entidade Operador tenho um atributo que é uma lista de telefones e mapeei m2m operador-telefone:
public class Operator {
	private Integer operatorId;
	private String name;
	private List<Telephone> telephones;
}

@ManyToMany
@JoinTable(name = "operator_telephone", joinColumns = @JoinColumn(name = "operator_id"), inverseJoinColumns = @JoinColumn(name = "telephone_id"))
public List<Telephone> getTelephones() {
	return telephones;
}
Modelei uma classe OperadorTelefone (mapeando m2O telefone e m2O operador) da seguinte maneira:
@Table(name = "operator_telephone")
public class OperatorTelephone implements Serializable {

	private Integer operatorTelephoneId;
	private Operator operator;
	private Telephone telephone;	

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "operator_telephone_id", unique = true, nullable = false)
	public Integer getOperatorTelephoneId() {
		return this.operatorTelephoneId;
	}	
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "operator_id", nullable = false)
	@NotNull
	public Operator getOperator() {
		return operator;
	}	

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "telephone_id", nullable = false)
	@NotNull
	public Telephone getTelephone() {
		return this.telephone;
	}

    //setters	
}

Na minha OperadorAction, tenho os seguintes métodos:
1 - getListTelephone(): cria uma lista do tipo Telefone, para que eu possa utilizar na view do JSF;
2 - saveOperator(): no método para salvar Operador, depois de persistir o mesmo eu crio um laço que, a cada iteração da listaTelefones, instancia um objeto OperadorTelefone e o persiste (ou deveria persistir, já que não funcionou). Segue o código:

public String saveOperator() {
	if (operator.getOperatorId() == null) {		
		entityManager.persist(operator);
		
		getListTelephone();
		for (int i = 0; i < listTelephone.size(); i++) {
			telephoneOperator = new OperatorTelephone();
			
			entityManager.persist(telephone);			
			telephoneOperator.setTelephone(listTelephone.get(i));
			telephoneOperator.setOperator(operator);
			entityManager.persist(telephoneOperator);				
		}		
	} 
	return "saveOperator";
}

@Factory("listTelephone")
public void getListTelephone() {
	listTelephone = new ArrayList<Telephone>();
	for (int i = 0; i < 2; i++) {
		telephone = new Telephone();
		listTelephone.add(i, telephone);			
	}
}
View operador_edit:
<a:repeat value="#{listTelephone}" var="_lt" id="listTelephone">
	<ui:define name="label">Telefone</ui:define>
	<h:inputText id="telephone" size="20" maxlength="10"
		value="#{telephone.number}" label="Telefone">
		<a:support event="onblur" reRender="telephoneDecoration"
			bypassUpdates="true" ajaxSingle="true" />			
	</h:inputText>					
</a:repeat>

Tenho quase certeza que deve existir uma maneira melhor de se fazer isso, algo "mágico" que o Hibernate faça, mas não consegui achar nada, se alguém puder dar umas dicas agradeço.

2 Respostas

marcelo.bellissimo

Quando você diz que “não funcionou”, o que exatamente não funcionou? Ele simplesmente não persistiu nenhuma das entidades que você criou ? Nem o operator, nem o telephone, nem as telephoneOperator ?

E essa linha aqui, não faz muito sentido estar presente aqui:

Voce está tentando persistir várias vezes a mesma entidade…

Está dando flush() em algum lugar? Se não estiver, pode ser esse o problema… se estiver e mesmo assim não estiver funcionando, então seja bem-vindo ao maravilhoso mundo do Seam, onde a persistência é realizada através de métodos obscuros, e nada é o que parece ser (sim, eu odeio Seam pela sua falta de transparência…) :roll:

S
marcelo.bellissimo:
Quando você diz que "não funcionou", o que exatamente não funcionou? Ele simplesmente não persistiu nenhuma das entidades que você criou ? Nem o operator, nem o telephone, nem as telephoneOperator ? E essa linha aqui, não faz muito sentido estar presente aqui:
entityManager.persist(telephone);
Voce está tentando persistir várias vezes a mesma entidade...

Está dando flush() em algum lugar? Se não estiver, pode ser esse o problema... se estiver e mesmo assim não estiver funcionando, então seja bem-vindo ao maravilhoso mundo do Seam, onde a persistência é realizada através de métodos obscuros, e nada é o que parece ser (sim, eu odeio Seam pela sua falta de transparência...) :roll:

E aí Marcelo, blz?

Então cara, agora está funcionando, refiz alguns métodos, criei uma lista de operadorTelefone ao invés de telefone (muita burrice não ter pensado nisso desde o início) e no método save() estou salvando de maneira correta também, de acordo com o indice da iteração, segue o que modifiquei:

@Factory("listOperatorTelephone")
public void getListOperatorTelephone() {
	listOperatorTelephone = new ArrayList&lt;OperatorTelephone&gt;();
	for (int i = 0; i &lt; 2; i++) {
		OperatorTelephone operatorTelephone = new OperatorTelephone();
		operatorTelephone.setTelephone(new Telephone());
		listOperatorTelephone.add(i, operatorTelephone);
	}
}

public String saveOperator() {
	if (operator.getOperatorId() == null) {
		
		entityManager.persist(email);
		entityManager.find(Email.class, email.getEmailId());
		operator.setEmail(email);			
		entityManager.persist(operator);
		
		for (int i = 0; i &lt; listOperatorTelephone.size(); i++) {
			// salva o número de telefone em telefone
			listOperatorTelephone.get(i).getTelephone().setNumber(listOperatorTelephone.get(i).getTelephone().getNumber());
			entityManager.persist(listOperatorTelephone.get(i).getTelephone());
			
			// salva os telefones e o operador em operador-telefone
			listOperatorTelephone.get(i).setTelephone(listOperatorTelephone.get(i).getTelephone());
			listOperatorTelephone.get(i).setOperator(operator);
			entityManager.persist(listOperatorTelephone.get(i));				
		}			
	} 
	return &quot;saveOperator&quot;;
}

view JSF

&lt;a:repeat value="#{listOperatorTelephone}" var="_telephone" id="listTelephone"&gt;
	&lt;s:decorate id="telephoneDecoration" template="../layout/edit.xhtml"&gt;
		&lt;ui:define name="label"&gt;Telefone&lt;/ui:define&gt;
		&lt;h:inputText id="telephone" size="20" maxlength="10"
			value="#{_telephone.telephone.number}" label="Telefone"&gt;
			&lt;a:support event="onblur" reRender="telephoneDecoration"
				bypassUpdates="true" ajaxSingle="true" /&gt;
			&lt;rich:jQuery selector="#telephone" query="mask('([telefone removido]')"
				timing="onload" /&gt;
		&lt;/h:inputText&gt;
	&lt;/s:decorate&gt;						
&lt;/a:repeat&gt;

Mas mesmo assim imagino que deva ter uma maneira mais "correta" de fazer isso, de um jeito mais fácil.

Abraços

Criado 27 de janeiro de 2010
Ultima resposta 28 de jan. de 2010
Respostas 2
Participantes 2