GORM Herança: como reaproveitar o registro da super classe?
Pessoal, antes de começar gostaria de dizer que tenho gostado muito do Grails.
Estamos conseguindo criar com muita facilidade uma aplicação que se feita em Java exigiria muito mais trabalho.
Pois é, facilidades a parte, vamos ao problema:
em uma herança, não consigo reaproveitar em uma subclasse o registro da SUPER CLASSE salvo por outra subclasse.
Possuo uma classe Pessoa da qual herdam várias outras, tais como Analista e Diretor.
Acontece que a mesma Pessoa é Analista e Diretor.
Quando salvo um Analista não consigo usar os mesmos dados dele para salvar um Diretor de forma que fique claro que são a mesma Pessoa.
Caso não queiram ler todo o post, penso que podem ir direto ao tópico "Simulando o problema:"
Na aplicação que estamos desenvolvendo um existem alguns conceitos que não possuem um CPF. É o caso do Projetista, que no nosso caso não possui CPF. Além do Projetista existem outros casos de pessoas sem CPF ou qualquer código único.
Um Analista é uma Pessoa e um Diretor também.
Estou usando a estratégia uma tabela para cada classe de domínio, para separar melhor os conceitos (tablePerHierarchy false).
Quando uma Pessoa possui um código identificador (no caso do CPF para o Diretor) este código é usado para ser o seu id.
Quando a Pessoa não possui um código identificador eu uso uma classe geradora de código e gero um id com 15 dígitos, que não pode ser confundido com o CPF ou com o CNPJ (existe também o conceito de Empresa, que possui CNPJ, mas que é irrelevante para o problema que preciso resolver).
Vejam a seguir o código a CLASSE Pessoa:
import utils.GeradorDeCodigo;
public final static String TIPO_PESSOA_FISICA = "PF";
public final static String TIPO_PESSOA_JURIDICA = "PJ";
BigInteger codigoIdentificador;
String nacionalidade="Brasileira";
String tipo = TIPO_PESSOA_FISICA;
static transients=['codigoIdentificador'];
table 'pf_pessoa'
sort 'nome'
id generator:'assigned',  column:'pes_id'
nome column:'pes_nome'
nacionalidade column:'pes_nacionalidade'
telefone column:'pes_telefone'
email column:'pes_email'
tipo column:'pes_tipo'
if ((this.codigoIdentificador) && (this.codigoIdentificador > 0)) {
this.id = this.codigoIdentificador;
this.id = GeradorDeCodigo.gerarProximo(Pessoa.class.getName());
Agora, vejam o código da CLASSE Analista:
class Analista extends Pessoa {
void setCpf(String value) {
// seta o Código Identificador do conceito de Pessoa
this.codigoIdentificador = new BigInteger(value);
table 'pf_analista'
id column: 'ana_id'
situacao column:'ana_situacao'
cpf column:'ana_cpf'
situacao(maxSize: 1, inList:["A", "I"])
cpf(size: 0..11, blank:true, nullable:true)
Por fim, vejam o código da CLASSE Diretor:
class Diretor extends Pessoa {
table 'pf_diretor'
id column: 'dr_id'
cpf column:'dr_cpf'
Com as classes acima, possuo no banco de dados as seguintes tabelas: pf_pessoa, pf_analista e pf_diretor;
Simulando o problema:
Para simular o problema criei um código que faz o seguinte:
1 - Cria e salva um Analista. Indiquei de propósito um CPF para ele.
2 - Cria um Diretor e tenta salvar com o mesmo CPF do Analista. Estou querendo indicar que esta Pessoa é aquela mesma Pessoa que é Analista.
class testeHerancaController {
def testar = {
Acionista oAcionista = new Acionista();
oAcionista.nome = "weber3";
oAcionista.email = "webermiranda3@sic.goias.gov.br";
oAcionista.telefone = "6232015536";
oAcionista.cpf = "12345678901";
oAcionista.save(flush:true);
Diretor oDiretor = new Diretor();
oDiretor.nome = "weber3";
oDiretor.email = "webermiranda3@sic.goias.gov.br";
oDiretor.telefone = "6232015536";
oDiretor.cpf = "12345678901";
oDiretor.save(flush:true); // ERRO AQUI
Quando eu mando salvar o Diretor (oDiretor.save) recebo um erro de chave duplicada no bacno de dados.
Neste exemplo eu simplifiquei a situação para facilitar o entendimento, mas os conceitos que herdam de Pessoa possuem vários atributos que diferenciam de um conceito para outro.
Como vou fazer para conseguir dizer que um Diretor é uma Pessoa que já existe em minha base de dados?
Valeu pela atenção e espero que possam me ajudar.
webermiranda,
Acredito que o seu problema seja conceitual e não do framework hibernate ou grails.
O que você ta querendo fazer é algo que java não aceita, Herança multipla. Eu digo isso pq para o hibernate, nessa situacao quando voce tiver um analista ou diretor, o hibernate passa a encarar essa instacia apenas como a sub classe e nao mais como apenas pessoa.
Se você mudar a relacao entre pessoa e analista e diretor, deixando de ser uma herança para ser um relacionamento muitos pra um, você conseguirá resolver seu problema.
igorhara tem razão, mesmo que Analista e Diretor sejam do tipo Pessoa o que você está persistindo no banco de dados é são as entidades Analista e Diretor e não pessoa. Acho que a solução que o igorhara citou é também é a melhor para resolver este teu problema!