Dúvida JPA - persist() vs merge()

E aí, pessoal.

Tem como vocês me ajudarem com uma dúvida?

eu estava tendo um problema ao persistir uma entidade com chave composta.

@Entity
@Table(name = "SUBTIPO", schema = "SCHEMA")
@IdClass(TipoPK.class)
public class SubTipo implements Serializable{

	private static final long serialVersionUID = 1L;

	@Id
	@SequenceGenerator(name = "SEQ_IDSUBTIPO", sequenceName = "SEQ_IDSUBTIPO", allocationSize = 1)
	@GeneratedValue(generator = "SEQ_IDSUBTIPO", strategy = GenerationType.SEQUENCE)
	@Column(name = "IDSUBTIPO", unique = true, nullable = false, precision = 22, scale = 0)
	private Long id;

	@Id
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "IDTIPO", referencedColumnName = "IDTIPO", nullable = false, insertable = false)
	private Tipo tipo;
	
}

Ou seja… é um objeto SubTipo que tem um Tipo, só que esse Tipo faz parte da PK

os Tipos ja estão gravados no banco, eu puxo uma lista deles e seto o que eu quero no meu subtipo
o id eu envio como nulo e tento dar um persist()

mas é lançada a exceção org.hibernate.PersistentObjectException: detached entity passed to persist
eu li que essa exceção é lançada quando você envia um objeto Persisted pra um método que espera um Transient.

eu imagino que ele dê esse erro porque uso uma chave composta, e mesmo tendo meu id como null, o Tipo está setado com um objeto persistido

ou seja, minha PK esta “meia” preenchida hehehe…
usando essa lógica eu pensei em usar o merge… e funcionou…

Existe alguma maneira melhor de se fazer isso?

Na verdade, esse erro costuma aparecer mais no seguinte cenário:

Cada entidade possui dois estados perante o motor ORM: gerenciada e não-gerenciada. Quando a entidade é gerenciada, quer dizer que você faz alterações nelas e essas alterações podem ser passadas para o banco “automagicamente”. Isso quer dizer que, em algum lugar, uma conexão está aberta e ouvindo as alterações que você faz na entidade. Acontece que, mesmo colocando uma entidade com Id populado no banco, ainda que esta entidade exista, ele vai reclamar que essa entidade não é gerenciada (e, portanto, o motor não “confia” nesse ID que você está passando). Ou seja, para resolver o seu problema, teoricamente você só precisa dar um “merge” na entidade (me parece que é a própria entidade Tipo) e esperar que ele popule automaticamente o outro atributo Id. Lógico, podem haver outros atributos que estejam ocasionando o problema, então, é uma questão de avaliar atributo por atributo da entidade para checar o que está acontecendo.

[]'s

Entendi…

a idéia então seria dar um merge na minha entidade Tipo tornando-a gerenciável, para poder dar um persist na entidade SubTipo?

Isso aí. A não ser que existam mais entidades na mesma situação nesta mesma entidade, isso deve resolver o problema.

é… não deu certo… deixei meu método assim

getEm().merge(subTipo.getTipo()); getEm().persist(subTipo);

e a mesma exceção foi lançada…

porém com

funciona… mas não parece certo usar merge pra uma entidade nova

A idéia não é usar merge() em uma entidade nova, mas sim, recuperar o estado de uma que já existe no banco de dados em relação a um objeto que você já possui. Se ele lançou a mesma exceção embaixo, pode ser que hajam outros atributos para serem tornados gerenciados ou - torça para não ser o caso - ele pode estar se perdendo em relação a usar uma chave composta em que um dos valores é uma sequence (não, nunca fiz isso para saber se funciona ou não).

[]'s

é… infelizmente eu acho que esse é o caso…

porque na minha classe só tem esse objeto Tipo, um Long e uma String…
não existem outras dependências…

esse relacionamento está causando problemas em algumas buscas também… realmente não sei por que…

acho que a melhor coisa é tentar conversar pra deixar essa PK somente com o número da sequence…