Como criar formulário para gravar dados em relação @OneToMany [Resolvido]

14 respostas
Guevara

Olá pessoal!
Fiz um relacionamento @OneToMany e as tabelas Contato e Mensagem foram criadas no banco. O problema agora é que ao criar o formulário para cadastro o Contato não possui mais campo mensagem e assunto e o que eu queria é gravar várias mensagens para o mesmo email,
Exemplo:
O usuario entra com [email removido], se existir no banco não cria outro registro em Contato, mas apenas mais um assunto e mensagem na tabela Mensagem.

@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long idContato;
	private String nome;
	private String email;
	@OneToMany(targetEntity=Mensagem.class ,cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "contato",orphanRemoval=true)
	private List<Mensagem> mensagens;
	
	public Contato() {
	}
	
	public Contato(Long idContato, String nome, String email,
	    List<Mensagem> mensagens) {
		this.idContato = idContato;
		this.nome = nome;
		this.email = email;
		this.mensagens = mensagens;
	}


	public List<Mensagem> getMensagens() {
		return mensagens;
	}

	public void setMensagens(List<Mensagem> mensagens) {
		this.mensagens = mensagens;
	}
//getters and setters

Classe Mensagem:

@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long idMensagem;
	private String assunto;
	private String mensagem;
	@ManyToOne
	private Contato contato;
	
	public String getAssunto() {
		return assunto;
	}
	public void setAssunto(String assunto) {
		this.assunto = assunto;
	}	
	
	public Mensagem() {
	}
	
	public Mensagem(Long idMensagem, String assunto, String mensagem,
			Contato contato) {
		this.idMensagem = idMensagem;
		this.assunto = assunto;
		this.mensagem = mensagem;
		this.contato = contato;
	}
// getters and setters

O Formulario:

<form action="contato/adiciona" method="post">
<li><label for="nome">Nome</label>
	<div><input name="contato.nome" class="element text small" type="text" maxlength="255" value="" />
	</div>
	</li>
	
	<li><label for="email">E-mail</label>	
	<div><input name="contato.email" class="element text large" type="text" maxlength="255" value="" />
	</div>
	</li>
	
	<li><label for="assunto">Assunto</label>	
	<div><input name="contato.assunto" class="element text large" type="text" maxlength="255" value="" />
	</div>
	</li>	
	
	<li><label for="mensagem">Mensagem</label>	
	<div><textarea name="contato.mensagem" class="element textarea large" rows="5" cols="80"></textarea>
	</div>
	</li> 

</ul>
<input type="submit" name="submit" value="Enviar" />
</form>

Como é mostrado, na classe Contato não existe mais atributo assunto e mensagem, pois estão na classe Mensagem. Tive a idéia de fazer assim:

<li><label for="assunto">Assunto</label>	
	<div><input name="mensagem.assunto" class="element text large" type="text" maxlength="255" value="" />
	</div>
	</li>	
	
	<li><label for="mensagem">Mensagem</label>	
	<div><textarea name="mensagem.mensagem" class="element textarea large" rows="5" cols="80"></textarea>
	</div>
	</li>

Classe ContatoDAO:

public void adiciona(Contato contato, Mensagem mensagem) {
		Transaction tx = session.beginTransaction();
		session.save(contato);
		session.save(mensagem);
		tx.commit();
	}

Ai beleza, salvou, mas está assim:

O que eu queria é salvar várias mensagens para o mesmo email, é isso que não tô sabendo fazer. =/
Abraço!!!

14 Respostas

Guevara
<li><label for="assunto">Assunto</label>	
	<div><input name="contato.mensagem.assunto" class="element text large" type="text" maxlength="255" value="" />
	</div>
	</li>	
	
	<li><label for="mensagem">Mensagem</label>	
	<div><textarea name="contato.mensagem.mensagem" class="element textarea large" rows="5" cols="80"></textarea>
	</div>
	</li>

Está salvando os dados do Contato mas esta parte não está salvando, nem o assunto e nem a mensagem. Numa relação @OneToMany é assim que fica o form?
Valeu!

Guevara

Esta é a StackTrace, só grava o nome e o email:

00:39:48,881 DEBUG [OgnlParametersProvider] Applying contato.nome with [ee]
00:39:48,969 DEBUG [OgnlParametersProvider] Applying contato.mensagem.mensagem with [rr]
00:39:48,975 DEBUG [OgnlParametersProvider] cant find property for expression contato.mensagem.mensagem ignoring
00:39:48,976 DEBUG [OgnlParametersProvider] Applying contato.email with [ee]
00:39:48,976 DEBUG [OgnlParametersProvider] Applying contato.mensagem.assunto with [rr]
00:39:48,977 DEBUG [OgnlParametersProvider] cant find property for expression contato.mensagem.assunto ignoring
00:39:48,978 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ContatoController.adiciona(Contato) as [contato]
00:39:48,978 DEBUG [ParametersInstantiatorInterceptor] Parameter values for [DefaultResourceMethod: ContatoController.adicionaContatoController.adiciona(Contato)] are [br.com.imobiliaria.bean.Contato@1a550f9]
00:39:49,001 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ExecuteMethodInterceptor
00:39:49,002 DEBUG [ExecuteMethodInterceptor] Invoking ContatoController.adiciona(Contato)
Hibernate: 
    insert 
    into
        Contato
        (email, nome) 
    values
        (?, ?)
00:39:49,556 DEBUG [DefaultLogicResult  ] redirecting to class ContatoController
00:39:49,558 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ContatoController.mensagem() as []
00:39:49,559 DEBUG [AsmBasedTypeCreator ] Trying to make class for ContatoController$mensagem$[telefone removido]$5
00:39:49,559 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for ContatoController.mensagem() as []
00:39:49,559 DEBUG [AsmBasedTypeCreator ] Parameter names found for creating type are: []
00:39:49,559 DEBUG [AsmBasedTypeCreator ] Methods: []
00:39:49,560 DEBUG [AsmBasedTypeCreator ] Fields: []
00:39:49,560 DEBUG [CacheBasedTypeCreator] cached generic type for method [DefaultResourceMethod: ContatoController.mensagemContatoController.mensagem()]
00:39:49,560 DEBUG [DefaultLogicResult  ] redirecting to /imobiliaria/mensagem
00:39:49,566 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor OutjectResult
00:39:49,570 DEBUG [ToInstantiateInterceptorHandler] Invoking interceptor ForwardToDefaultViewInterceptor
00:39:49,571 DEBUG [ForwardToDefaultViewInterceptor] Request already dispatched and commited somewhere else, not forwarding.
00:39:49,571 DEBUG [VRaptor             ] VRaptor ended the request

Alguém poderia ajudar por favor? Já tentei de td quanto é jeito pra ele achar o parâmetro certo no form.
Abraço!

thiagotn

De acordo com seu form, uma solução para salvar uma mensagem, de cada vez, para um usuário. Primeiro você poderia ajustar seu formulário, deixando o ‘name’ desta forma:

Assunto...
<input name="mensagem.assunto" class="element text large" type="text" maxlength="255" value="" />

Mensagem...
<textarea name="mensagem.mensagem" class="element textarea large" rows="5" cols="80"></textarea>

E declarar como um dos parâmetros do método do seu Controller, além do próprio Contato, o atributo Mensagem. Algo como isto:

public void adiciona(Contato contato, Mensagem mensagem){
		List<Mensagem> mensagens = new ArrayList<Mensagem>();
		mensagens.add(mensagem);
		contato.setMensagens(mensagens);
		dao.salva(contato);
		result.redirectTo(ContatoController.class).lista();
	}
Guevara

Opa, e ai thiagotn!
Vou testar aqui, assim que terminar eu retorno dizendo se deu certo. Obrigado pela resposta! =)
Abraço!!!

Guevara

Oi thiagotn!
Tentei como vc sugeriu, mas não salva a fk do contato:

Instanciar Mensagem junto com Contato não está dando certo. =/
Até agora não descobri como persistir uma relação @OneToMany.

Guevara

Finalmente consegui resolver a questão, a dica é alterar o Controller e o DAO tb, além de deixar o form para persistir o objeto em questão, sem associação ao outro.

Na imagem as IDs de mensagem e contato são iguais pq zerei o banco e gravei apenas uma mensagem, sendo mais mensagens a ID de mensagem aumenta mas a ID do contato permanece a mesma.
Abraço!

Leandro-SP

Guevara:
Oi thiagotn!
Tentei como vc sugeriu, mas não salva a fk do contato:

Instanciar Mensagem junto com Contato não está dando certo. =/
Até agora não descobri como persistir uma relação @OneToMany.

Guevara,
Fiz o mesmo esquema que você, está gravando ok nas duas tabelas, porém a FK da segunda tabela nao está gravando… qual a dica para gravar o FK da segunda tabela?
O FK da segunda tabela tem que ser igual ao PK da primeira tabela.

Pode me socorrer por favor?

Obrigado.
Att,
Leandro.

Leandro-SP

Acho que consegui!

No Controller tem que setar os dois lados do relacionamento do banco:
Exemplo:

public void adiciona(Contato contato, Mensagem mensagem){  
        List<Mensagem> mensagens = new ArrayList<Mensagem>();  
        mensagens.add(mensagem);  
        contato.setMensagens(mensagens);  
        mensagem.setContato(contato); //IMPORTANTE
        dao.salva(contato);  
        result.redirectTo(ContatoController.class).lista();  
    }

É isso mesmo?

Leandro-SP

Opa!

Por exemplo e se eu quiser adicionar mais de um assunto e mais de uma mensagem para cada usuario no meu banco de dados dentro do mesmo form?

Assunto...  
 <input name="mensagem.assunto" class="element text large" type="text" maxlength="255" value="" />  
   
 Mensagem...  
 <textarea name="mensagem.mensagem" class="element textarea large" rows="5" cols="80"></textarea> 

 Assunto...  
 <input name="mensagem.assunto" class="element text large" type="text" maxlength="255" value="" />  
   
 Mensagem...  
 <textarea name="mensagem.mensagem" class="element textarea large" rows="5" cols="80"></textarea>

Tentei fazer isso dai mas deu erro:

23:53:44,953 DEBUG [OgnlParametersProvider] Applying mensagem.assunto with [Teste1, Teste2]
ognl.OgnlException: assunto [br.com.caelum.vraptor.VRaptorException: Unable to find converter for java.lang.String]
Lucas_Cavalcanti

se vc quer adicionar mais de uma mensagem, vc precisa receber uma List (ou Mensagem[]) na sua lógica, e colocar índices nos inputs… mensagem[0].assunto, etc

Leandro-SP

Consegui:

Assunto...  
 <input name="mensagem[0].assunto" class="element text large" type="text" maxlength="255" value="" />  
   
 Mensagem...  
 <textarea name="mensagem[0].mensagem" class="element textarea large" rows="5" cols="80"></textarea> 

 Assunto...  
 <input name="mensagem[1].assunto" class="element text large" type="text" maxlength="255" value="" />  
   
 Mensagem...  
 <textarea name="mensagem[1].mensagem" class="element textarea large" rows="5" cols="80"></textarea>

Controller:

public void adiciona(Contato contato, List<Mensagem> mensagem){  
        for (Mensagem mensagens : mensagem){  
		mensagem.setContato(contato);
		dao.salva(contato, mensagens);
	}
        result.redirectTo(ContatoController.class).lista();  
    }

Agora está ok. O único porém é que o meu DAO está listando 2x cada contato, pois existem duas mensagens para cada contato. Se for olhar a tabela de contato está ok só existe um contato mesmo. Preciso descobrir dentro do DAO como trazer uma linha só com as duas mensagens para cada contato. Help meee!
Obrigado.
Att,
Leandro.

Leandro-SP

Nada como pesquisar no Guj:

public List<Contato> listaTudo() { return this.session.createCriteria(Contato.class) .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) .list(); }

Agora posso ir dormir!
Obrigado.
Att,
Leandro.

sauron_fight

Estou com um problema parecido, estou fazendo um sistema de venda de produtos
com isso quero vender varios produtos em uma mesma venda, uma coisa que nao
entendi e como gravar e refernciar 20 itens da tabela produto a uma mesma venda?
Como ficaria no banco?

Agradeço a todos

Guevara

Maravilha Leandro-SP ! Bom que tenha resolvido.
Pelo visto este tópico está sendo bastante útil. =)

Criado 23 de abril de 2010
Ultima resposta 31 de ago. de 2010
Respostas 14
Participantes 5