Hibernate: @OneToMany e @Any

12 respostas
d34d_d3v1l

Galera,

Quero fazer uma ‘troca de mensagens’ em um sistema. Então, tenho uma interface Autenticavel, que seria:
Medico, Paciente e Funcionario. Tenho o Remetente na classe Mensagem, e tenho uma collection de mensagens em cada uma
das entidades (como destinatario).

A seguir o código da classe Mensagem:

@Entity
@Table(name="mensagens")
public class Mensagem{
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer codigo;
	
	@Column(length=100)
	private String titulo;
	
	@Column(columnDefinition="TEXT")
	private String mensagem;
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date data;
	
	@Column(columnDefinition="TINYINT(1) DEFAULT 0")
	private Boolean lida = false;

	@Any(metaColumn = @Column(name = "tipo_emissor"), optional = false)
	@AnyMetaDef(idType = "integer", metaType = "string", metaValues =
	{
			@MetaValue(value = "M", targetEntity = Medico.class),
			@MetaValue(value = "P", targetEntity = Paciente.class),
			@MetaValue(value = "F", targetEntity = Funcionario.class) })
	@JoinColumn(name = "codigo_emissor")
	private Autenticavel remetente;

Agora trechos de código das classes que implementam Autenticavel:

//medico
@OneToMany(cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinTable(name="mensagens_do_medico", joinColumns=@JoinColumn(columnDefinition="medico_id"),
				inverseJoinColumns=@JoinColumn(columnDefinition="mensagem_codigo"))
	@Sort(type=SortType.NATURAL)
	private SortedSet<Mensagem> mensagens;

//paciente

	@OneToMany(cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinTable(name="mensagens_do_paciente", joinColumns=@JoinColumn(columnDefinition="paciente_id"),
				inverseJoinColumns=@JoinColumn(columnDefinition="mensagem_codigo"))
	@Sort(type=SortType.NATURAL)
	private SortedSet<Mensagem> mensagens;
	

//funcionario

	@OneToMany(cascade=javax.persistence.CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinTable(name="mensagens_do_funcionario", joinColumns=@JoinColumn(columnDefinition="funcionario_codigo"),
				inverseJoinColumns=@JoinColumn(columnDefinition="mensagem_codigo"))
	@Sort(type=SortType.NATURAL)
	private SortedSet<Mensagem> mensagens;

Bom, o que acontece é que vou fazer um form para cadastrar no banco uma mensagem. Tambem vou ter um campo
para selecionar os destinatários. Mas eu tenho um ‘portal’ para cada tipo de usuario. Se for Medico ele tera o crud da mensagem
onde o usuario setado já sera registrado como remetente. E idem para o Paciente e Funcionario. Minha dúvida:
se vou registrar uma entidade do tipo Mensagem no banco de dados

(ou seja:)

meuDao.save(mensagem);

como eu vou fazer para inserir também os destinatários, sendo que na entidade mensagem eu não tenho um array de “Autenticavel”???

abraços

12 Respostas

drsmachado

Vamos deixar de lado a parte da codificação e pensar na lógica do problema.
1 - Cada mensagem tem um rementente. Ok.
2 - Cada mensagem é enviada para 1 destinatário apenas? Ou mais de um, ao mesmo tempo?

Em todo caso, não vejo alternativa senão inserir um atributo que referencie ao destinatário ou à coleção de destinatários em mensagem. Isso forçaria um relacionamento N : M e, por conseguinte, uma tabela associativa.

d34d_d3v1l

Obrigado pela resposta.

Para vários destinatários.

O hibernate ja gerou as tabelas:
mensagens_do_medico
mensagens_do_paciente
mensagens_do_funcionario

drsmachado

Como é para vários, entendo tratar-se de relacionamento 1 : N. Onde 1 mensagem pode ser enviada para vários destinatários.
Logo, não é viável deixar as chaves estrangeiras em mensagem e sim, nos destinatários.
O que acaba complicando é que existem 3 tabelas distintas e cada uma delas pode ser um destinatário.
O que eu faria. Criaria uma entidade chamada Destinatario e nela um atributo Autenticavel (que, por ser uma interface, poderia representar qualquer um dos destinatarios) e em Mensagem, criaria um atributo Collection de Destinatario.
Neste caso, forço o hibernate a criar uma tabela destinatario que serviria de associativa para Mensagem e os vários possíveis tipos de destinatários.

d34d_d3v1l

Mas por que não funcionaria jogar uma Collection de Autenticavel
direto na classe Mensagem?

Na verdade,
antes eu tinha modelado
N : N, e tinha colocado na classe Mensagem
um Array de cada entidade separada…

Mas ai meu amigo fez essa modelagem, que ficou
mais limpa, mais elegante. Porém agora estou
em dúvida de como fazer o insert…

Se eu pegasse a lista do destinatarios e fizesse um update
em cada um deles setando a Mensagem, funcionaria… Mas seria mto
porco tbem né?

:frowning:

drsmachado

O relacionamento é 1 : N, certo?
Você acabaria com uma nova coluna em cada uma das tabelas que representam os autenticaveis.
Se prefere, também é possível.

drsmachado

Aí é que está. Eu ainda acho que é um relacionamento N : N e não apenas 1 : N.
Cada mensagem pode ser enviada para um ou vários destinatários e cada destinatário pode ter mais de uma mensagem (ou nenhuma).
Sendo assim, obrigatoriamente, precisa do array de destinatários.

Esqueça o banco de dados, como você vai associar mensagem e destinatário no sistema rodando? Como saberá para quem é a mensagem?

d34d_d3v1l

Quando o usuario logar eu posso fazer um

getMensagens();

ja que em cada usuario do tipo “Autenticavel” eu tenho esse método.
E para saber quem enviou :

mensagem.getRemetente();
drsmachado
E quando eu estiver enviando mensagem, você vai setar em cada um dos possíveis destinatários?

au1.setMensagem(msg);

aut2.setMensagem(msg);

aut3.setMensagem(msg);

(ou usando um laço)?

Não seria mais adequado colocar um combo para selecionar os destinatários e, então, definir isso em uma lista na mensagem?
d34d_d3v1l

Sim, acredito que esta seria a solução.

Mas como seria a anotação, tendo em vista as 3 tabelas que o Hibernate criou com
as anotações em cada classe?

Ou deveria desconsiderá-las e fazer de novo?

pq o array seria do tipo Autenticavel na classe Mensagem, entraria o Any aí novamente…

putz O.o’

drsmachado

d34d_d3v1l:
Sim, acredito que esta seria a solução.

Mas como seria a anotação, tendo em vista as 3 tabelas que o Hibernate criou com
as anotações em cada classe?

Ou deveria desconsiderá-las e fazer de novo?

pq o array seria do tipo Autenticavel na classe Mensagem, entraria o Any aí novamente…

putz O.o’


E é aí que entra aquele exemplo que citei.
O que eu percebo é que todo o problema é o uso de uma interface ali. Talvez uma classe abstrata pudesse resolver e, então, teríamos que tratar uma relação de herança. Mas não consigo dizer se é a melhor abordagem, normalmente, herança envolve coisas que mais complicam que facilitam.

d34d_d3v1l

Um @ManyToAny ?

drsmachado

Camarada, eu não curto ficar usando as anotações do hibernate. Prefiro as do JPA mesmo.
Se você quiser arriscar, não boto a mão no foto.
Por experiência, se é preciso usar algo fora do JPA padrão, é por que a modelagem está, no mínimo, não ortodoxa, eventualmente, errada.

Criado 21 de junho de 2012
Ultima resposta 21 de jun. de 2012
Respostas 12
Participantes 2