JPA. Problema muito estranho

4 respostas
wagner_a_lima

É o sequinte:
Tenho 3 entidades: Funcionario, Endereco e Cidade mapeadas da seguinte forma:

Um funcionário tem uma naturalidade (instância de cidade) e um endereco. Este último possui uma cidade (outra instância de cidade).
Quando busco um funcionário que nasceu em São Paulo (id = 51) e que mora em Manaus (id=60) o hibernate/jpa cria corretamente duas instâncias de cidade: uma para a naturalidade do funcionário e outra para o endereço.

O problema é que quando o funcionário nasceu em São Paulo (id = 51) e mora em São Paulo (id=51) ele (hibernate/jpa) cria somente uma instância para as duas cidades.

Se eu altero o valor da naturalidade, por serem a mesma instância, automaticamente (como é de se esperar) ele altera a cidade do endereço.

Alguém já passou por algo semelhante?

@Entity(name = "Funcionario")
public class Funcionario implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nome;
    @ManyToOne(cascade = CascadeType.ALL, optional = false)
    @JoinColumn(name = "idEndereco", referencedColumnName = "id", nullable = false)
    private Endereco endereco;
    @ManyToOne
    @JoinColumn(name = "idCidadeNaturalidade", referencedColumnName = "id")
    private Cidade naturalidade;

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Funcionario other = (Funcionario) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 67 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }
}
@Entity(name = "Endereco")
public class Endereco implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String logradouro;
    private String numero;
    @ManyToOne
    @JoinColumn(name = "idCidade", referencedColumnName = "id")
    private Cidade cidade;
 
   @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Endereco other = (Endereco) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 41 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

}
@Entity(name = "Cidade")
public class Cidade implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nome;
    @OneToMany(mappedBy = "naturalidade")
    private List<Funcionario> funcionarios;

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Cidade other = (Cidade) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 41 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

4 Respostas

dbconrado

Mas este comportamento é normal e o mais correto.

Se vc quer alterar a cidade natal do cara, tem que atribuir outra instância de Cidade.

não entendi pq isto é um problema.

abs

wagner_a_lima

O problema é que se eu alterar a cidade de nascimento do funcionário não necessariamente deveria alterar a cidade do endereço.

Como está sendo criado uma instância (referência em memória) para a naturalidade e para a cidade do endereço, não consigo esta independência.

Quando faço um debug, posso ver que a instância da naturalidade é a mesma da cidade do endereço.

Ficou mais claro? Se não tiver claro, tento explicar melhor.

Valeu.

wagner_a_lima

Será que é algum problema em meus relacionamentos ou é alguma estatégia específica do JPA?

Alguém???

dbconrado

vamos tentar traduzir em tabelas.
(exemplos de nomes)

vc tem 3: FUNCIONARIO, ENDERECO E CIDADE.

FUNCIONARIO possui COD_ENDERECO e COD_CID_NATAL, certo?

ENDERECO possui COD_CIDADE… e é tudo chave estrangeira.

CIDADE possui CODIGO (primária)

vc quer alterar COD_CID_NATAL e não quer que COD_CIDADE seja alterada, né?

pois bem…

o problema é que o objeto Cidade referencia o mesmo registro de cidade (referenciam o mesmo código de cidade, ou seja, mesma chave primária).

Se vc quer alterar a cidade de São Paulo para Rio de Janeiro, vc deve buscar no banco a cidade Rio de Janeiro e “setar” no seu funcionário.

Se Rio de Janeiro não existe, vc tem que criar um objeto Cidade e atribuir o nome nele.
Daí, quando vc realizar o merge, esta Cidade será inserida na tabela CIDADE.

Espero ter ajudado

Criado 20 de novembro de 2009
Ultima resposta 20 de nov. de 2009
Respostas 4
Participantes 2