[Resolvido] Salvar e listar campo pertencente a chave estrangeira

Boa tarde,

tenho o seguinte formulário de cadastro de viatura:

    <%@ page language="java" contentType="text/html; charset=UTF-8"  
        pageEncoding="UTF-8"%>  
      
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>  
      
    <form action="<c:url value="/viaturas"/>" method="POST">  
        <fieldset>  
            <legend>Adicionar Viatura</legend>  
      
            <label for="prefixo">Prefixo:</label> <input id="prefixo" type="text"  
                name="viatura.prefixo" value="${viatura.prefixo}" /> <label  
                for="placa">Placa:</label> <input id="placa" type="text"  
                name="viatura.placa" value="${viatura.placa}" /> <label for="marca">Marca:</label>  
            <input id="marca" type="text" name="viatura.marca"  
                value="${viatura.marca}" /> <label for="modelo">Modelo:</label> <input  
                id="modelo" type="text" name="viatura.modelo" value="${viatura.modelo}" /> <label  
                for="tipoVeiculo">Tipo Veículo:</label> <input id="tipoVeiculo"  
                type="text" name="viatura.tipoVeiculo" value="${viatura.tipoVeiculo}" /> <label  
                for="unidades">Selecione uma unidade:</label> <select  
                name="viatura.unidade.codUnidade" id="unidades">  
                <c:forEach var="unidade" items="${unidades}">  
                    <option value="${unidade.codUnidade}">${unidade.nomeUnidade}</option>  
                </c:forEach>  
            </select>  
            <button type="submit">Enviar</button>  
        </fieldset>  
    </form>  

a classe Viatura.java

    package br.com.sisco.modelo;  
      
    import javax.persistence.Column;  
    import javax.persistence.Entity;  
    import javax.persistence.GeneratedValue;  
    import javax.persistence.Id;  
    import javax.persistence.JoinColumn;  
    import javax.persistence.ManyToOne;  
    import javax.persistence.Table;  
      
    @Entity  
    @Table(name = "viatura")  
    public class Viatura {  
      
        @Id  
        @GeneratedValue  
        @Column(name = "cod_viatura")  
        private Long codViatura;  
      
        @Column(unique = true, nullable = false)  
        private Long prefixo;  
      
        @Column(length = 50, nullable = false)  
        private String marca;  
      
        @Column(length = 50, nullable = false)  
        private String modelo;  
      
        @ManyToOne(optional = false)  
        @JoinColumn(name = "cod_unidade")  
        private Unidade codUnidade = new Unidade();  
      
        @Column(length = 10, nullable = false)  
        private String placa;  
      
        @Column(name = "tipo_veiculo", length = 10, nullable = false)  
        private String tipoVeiculo;  
      
        @Column(name = "viatura_ativa")  
        private boolean viaturaAtiva = true;  
      
        public Long getCodViatura() {  
            return this.codViatura;  
        }  
      
        public void setCodViatura(Long codViatura) {  
            this.codViatura = codViatura;  
        }  
      
        public Long getPrefixo() {  
            return this.prefixo;  
        }  
      
        public void setPrefixo(Long prefixo) {  
            this.prefixo = prefixo;  
        }  
      
        public String getMarca() {  
            return this.marca;  
        }  
      
        public void setMarca(String marca) {  
            this.marca = marca;  
        }  
      
        public String getModelo() {  
            return this.modelo;  
        }  
      
        public void setModelo(String modelo) {  
            this.modelo = modelo;  
        }  
      
        public String getPlaca() {  
            return this.placa;  
        }  
      
        public void setPlaca(String placa) {  
            this.placa = placa;  
        }  
      
        public String getTipoVeiculo() {  
            return this.tipoVeiculo;  
        }  
      
        public void setTipoVeiculo(String tipoVeiculo) {  
            this.tipoVeiculo = tipoVeiculo;  
        }  
      
        public Unidade getCodUnidade() {  
            return this.codUnidade;  
        }  
      
        public void setCodUnidade(Unidade codUnidade) {  
            this.codUnidade = codUnidade;  
        }  
      
        public boolean isViaturaAtiva() {  
            return this.viaturaAtiva;  
        }  
      
        public void setViaturaAtiva(boolean viaturaAtiva) {  
            this.viaturaAtiva = viaturaAtiva;  
        }  
    }  

a viaturasController.java

    package br.com.sisco.controller;  
      
    import java.util.List;  
      
    import br.com.caelum.vraptor.Delete;  
    import br.com.caelum.vraptor.Get;  
    import br.com.caelum.vraptor.Path;  
    import br.com.caelum.vraptor.Post;  
    import br.com.caelum.vraptor.Put;  
    import br.com.caelum.vraptor.Resource;  
    import br.com.caelum.vraptor.Result;  
    import br.com.sisco.dao.UnidadeDao;  
    import br.com.sisco.dao.ViaturaDao;  
    import br.com.sisco.modelo.Viatura;  
      
      
    @Resource  
    public class ViaturasController {  
      
        private final ViaturaDao dao;  
        private final Result result;  
        //private Validator validator;  
        private final UnidadeDao unidadeDao;  
          
        public ViaturasController(ViaturaDao dao, Result result,UnidadeDao unidade){  
              
            this.dao = dao;  
            this.result = result;  
            this.unidadeDao = unidade;  
        }  
        @Get  
        @Path("/viaturas/novo")  
        // acessa o formulario para cadastro da viatura  
        public void formulario() {  
            result.include("unidades", unidadeDao.listaTudo());  
        }  
      
        @Get  
        @Path("/viaturas/{codViatura}")  
        // exibe os campos com os dados a serem alterados  
        public Viatura edita(Long codViatura) {  
            return dao.carrega(codViatura);  
        }  
      
        @Put  
        @Path("/viaturas/{viatura.codViatura}")  
        // logica para alterar a viatura  
        public void altera(Viatura viatura) {  
            dao.edita(viatura);  
            result.redirectTo(this).lista();  
        }  
      
        @Post  
        @Path("/viaturas")  
        // logica para adicionar viaturas  
        public void adiciona(Viatura viatura) {  
            dao.salva(viatura);  
            result.redirectTo(ViaturasController.class).lista();  
        }  
      
        @Delete  
        @Path("/viaturas/{codViatura}")  
        // logica para remover a viatura  
        public void remove(Long codViatura) {  
            Viatura viatura = dao.carrega(codViatura);  
            dao.remove(viatura);  
            result.redirectTo(this).lista();  
        }  
      
        @Get  
        @Path("/viaturas")  
        // lógia que lista as viaturas  
        public List<Viatura> lista() {  
            return dao.listaTudo();  
        }  
    }  

e essa e a viatuaDao.java

[code] package br.com.sisco.dao;

import java.util.List;  
  
import org.hibernate.Session;  
import org.hibernate.Transaction;  
  
import br.com.caelum.vraptor.ioc.Component;  
import br.com.sisco.modelo.Viatura;  
  
@Component  
public class ViaturaDao {  
  
    private final Session session;  
  
    public ViaturaDao(Session session) {  
        this.session = session;  
    }  
  
    public List<Viatura> listaTudo() {  
        // metodo list() - lista todos os registros  
        return this.session.createCriteria(Viatura.class).list();  
    }  
  
    // metodo para salvar a viatura  
    public void salva(Viatura viatura) {  
        Transaction tx = session.beginTransaction();  
        session.save(viatura);  
        tx.commit();  
    }  
  
    // metodo para alterar a viatura  
    public void edita(Viatura viatura) {  
        Transaction tx = session.beginTransaction();  
        session.update(viatura);  
        tx.commit();  
    }  
  
    // carrega os dados da viatura selecionada  
    public Viatura carrega(Long codViatura) {  
        return (Viatura) this.session.load(Viatura.class, codViatura);  
    }  
  
    // metodo para remover a viatura do banco de dados  
    public void remove(Viatura viatura) {  
        Transaction tx = session.beginTransaction();  
        this.session.delete(viatura);  
        tx.commit();  
    }  
}  

[/code]
e essa e a lista.jsp da viatura

[code] <%@ page language=“java” contentType="text/html; charset=UTF-8"
pageEncoding=“UTF-8”%>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c”%>

<table>  
    <thead>  
        <tr>  
            <th>Prefixo</th>  
            <th>Placa</th>  
            <th>Marca</th>  
            <th>Modelo</th>  
            <th>Tipo</th>  
            <th>Unidade</th>  
              
        </tr>  
    </thead>  
    <tbody>  
        <c:forEach items="${viaturaList}" var="viatura">  
            <tr>  
                <td>${viatura.prefixo}</td>  
                <td>${viatura.placa}</td>  
                <td>${viatura.marca}</td>  
                <td>${viatura.modelo}</td>  
                <td>${viatura.tipoVeiculo}</td>  
                <td>${viatura.codUnidade}</td>  
                <td><a href="<c:url value="/viaturas/${viatura.codViatura}"/>">Editar</a></td>  
                <td>  
                    <form action="<c:url value="/viaturas/${viatura.codViatura}"/>"  
                        method="POST">  
                        <button class="link" name="_method" value="DELETE">Remover</button>  
                    </form>  
                </td>  
            </tr>  
        </c:forEach>  
    </tbody>  
</table>  

[/code]

o problema é que quando eu vou salvar a viatura aparece a seguinte exception:

    HTTP Status 500 -  
      
    type Exception report  
      
    message  
      
    description The server encountered an internal error () that prevented it from fulfilling this request.  
      
    exception  
      
    br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade  
        br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:96)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:93)  
        br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44)  
        br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)  
        br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)  
        br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)  
      
    root cause  
      
    org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade  
        org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)  
        org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)  
        org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)  
        org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)  
        org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)  
        org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)  
        org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)  
        org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)  
        org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)  
        org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:562)  
        org.hibernate.impl.SessionImpl.save(SessionImpl.java:550)  
        org.hibernate.impl.SessionImpl.save(SessionImpl.java:546)  
        br.com.sisco.dao.ViaturaDao.salva(ViaturaDao.java:28)  
        br.com.sisco.controller.ViaturasController.adiciona(ViaturasController.java:57)  
        sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
        sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  
        sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  
        java.lang.reflect.Method.invoke(Method.java:616)  
        br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:61)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:93)  
        br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)  
        br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)  
        br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)  
        br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44)  
        br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)  
        br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)  
        br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)  
      
    note The full stack trace of the root cause is available in the Apache Tomcat/6.0.35 logs.  
    Apache Tomcat/6.0.35  

e na lista de viatura esta aparecendo br.com.sisco.modelo.Unidade@1680bc6 onde deveria aparecer a codUnidade.

Cara, quando você for postar, evite colocar esse monte de código… tem muita gente que não ler. Eu por exemplo sou um deles.

Eu só li sua exception: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade

Esse campo deve ser preenchido e está null.

Veja se no seu banco de dados não existe esse campo null.

[quote=jakefrog]Cara, quando você for postar, evite colocar esse monte de código… tem muita gente que não ler. Eu por exemplo sou um deles.

Eu só li sua exception: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade

Esse campo deve ser preenchido e está null.

Veja se no seu banco de dados não existe esse campo null.[/quote]

Concordo com o jakefrog em ambos os argumentos - texto grande não da muita vontade de ler - verifique ai se o seu banco aceita null nesse atributo.

not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade

se esse codUnidade não tá null, salve esse cara no banco antes de salvar a viatura.

[quote=Lucas Cavalcanti]not-null property references a null or transient value: br.com.sisco.modelo.Viatura.codUnidade

se esse codUnidade não tá null, salve esse cara no banco antes de salvar a viatura.[/quote]

o codUnidade não pode ser null, e ele se refere a outra tabela no banco de dados que se chama unidade. Deixei ele no select do formulario e esse select tem o value = codUnidade que já existe no banco de dados.

O jeito que eu fiz para salvar a viatura esta errado? Salvar o codUnidade junto com os outros dados da viatura? Qual seria o jeto correto para funcionar?

o ideal é mapear o relacionamento com unidade do que mapear a chave estrangeira.

algo como:

@ManyToOne
@JoinColumn(name="codUnidade")
private Unidade unidade;

e vc salva passando uma unidade com o id preenchido.

[quote=Lucas Cavalcanti]o ideal é mapear o relacionamento com unidade do que mapear a chave estrangeira.

algo como:

@ManyToOne
@JoinColumn(name="codUnidade")
private Unidade unidade;

e vc salva passando uma unidade com o id preenchido.[/quote]

Lucas Cavalcante,

fiz essa alteração que vc sugeriu e também mudei o nome do meu select para “viatura.unidade.codUnidade” e funcionou!

Obrigado pela a ajuda!