[Resolvido]ManyToMany com campos adicionais

Boa tarde pessoal, estou estudando JPA/hibernate e consegui tirar varias dúvidas pesquisando pelo fórum, porém empaquei em uma questão e não achei nenhuma solução até agora.

É o seguinte, estou acompanhando um tutorial do Hebert Coelho(JPA-Mini-livro) e estou tentando implementar um relacionamento ManyToMany com campos adicionais, onde tenho as tabelas: categoria; tamanho; categoriaTamanho e na tabela categoriaTamanho tenho um atributo “preco” (preço).

Até ai tudo bem, porém eu estou tentando alterar uma categoria, adicionando uma lista de “categoriaTamanho” (que por enquanto estou testando com somente 1 objeto). Só que a tabela categoriaTamanho não é atualizada durante o processo.

Alguem saberia me dizer o que estou fazendo de errado?

Segue abaixo o código:

Categoria:

@Entity
@Table(name = "categoria")
public class Categoria implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 4860749609685809786L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;

	private String nome;

	private int calzone;

	private int status;

	@OneToMany(mappedBy = "categoria")
	private List<ProdutoVariavel> produtosVariaveis;

	@OneToMany(mappedBy = "categoria")
	private List<CategoriaTamanho> tamanhos;

//getters and setters e etc...

Tamanho:

@Entity
@Table(name = "tamanho_pizza")
public class Tamanho implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -323623018617588835L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	
	private String nome;
	
	private int pedacos;
	
	@Column(name="qtd_sabores")
	private int quantidadeSabores;
	
	private int status;
	
	@OneToMany(mappedBy = "tamanho")
	private List<CategoriaTamanho> categorias;

//getters and setters e etc...

CategoriaTamanho

@Entity
@IdClass(CategoriaTamanhoID.class)
@Table(name = "categoriaTamanho")
public class CategoriaTamanho implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1145594767666232939L;

	@Id
	@ManyToOne
	@JoinColumn(name="id_categoria")
	private Categoria categoria;
	
	@Id
	@ManyToOne
	@JoinColumn(name="id_tamanho")
	private Tamanho tamanho;
	
	@Column(name="preco_pizza")
	private double precoPizza;

//getters and setters e etc...

CategoriaTamanhoID

public class CategoriaTamanhoID implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -6886310238389615698L;
	private int tamanho;
	private int categoria;
	
	public CategoriaTamanhoID(){
		
	}
//getters and setters e etc...

Pequeno método que estou usando para testar:

 	public String DefinirPreco(int categoriaID){
		tamanho = tamanhoDAO.pesquisar(1);
		categoria = categoriaDAO.pesquisar(categoriaID);
		categoriaTamanho.setTamanho(tamanho);
		categoriaTamanho.setCategoria(categoria);
		categoriaTamanho.setPrecoPizza(20.30);
		tamanhos.add(categoriaTamanho);
		categoria.setTamanhos(tamanhos);
		
		categoriaDAO.atualizar(categoria);
		
		return "sucesso";
	}

Opa, falha minha o proximo tópico do livro era o cascade. :slight_smile:

Então fiz a seguinte alteração em “categoria”:

@OneToMany(cascade = CascadeType.ALL,mappedBy = "categoria")
	private List<CategoriaTamanho> tamanhos;

Só que agora está dando o erro:

detached entity passed to persist: sisapi.model.Tamanho

Resolvido. Achei a solução nesse link: http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/

Segue abaixo como ficaram minhas entidades:

@Entity
@Table(name = "categoria")
public class Categoria {


	private int id;
	private String nome;
	private int calzone;
	private int status;
	private List<ProdutoVariavel> produtosVariaveis;
	private List<CategoriaTamanho> tamanhos;

	public Categoria(){
	}
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public int getCalzone() {
		return calzone;
	}

	public void setCalzone(int calzone) {
		this.calzone = calzone;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	@OneToMany(mappedBy = "categoria")
	public List<ProdutoVariavel> getProdutosVariaveis() {
		return produtosVariaveis;
	}

	public void setProdutosVariaveis(List<ProdutoVariavel> produtosVariaveis) {
		this.produtosVariaveis = produtosVariaveis;
	}

	@SuppressWarnings("deprecation")
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.categoria",cascade = 
	{CascadeType.PERSIST, CascadeType.MERGE})
	@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
	public List<CategoriaTamanho> getTamanhos() {
		return tamanhos;
	}

	public void setTamanhos(List<CategoriaTamanho> tamanhos) {
		this.tamanhos = tamanhos;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + calzone;
		result = prime * result + id;
		result = prime * result + ((nome == null) ? 0 : nome.hashCode());
		result = prime
				* result
				+ ((produtosVariaveis == null) ? 0 : produtosVariaveis
						.hashCode());
		result = prime * result + status;
		result = prime * result
				+ ((tamanhos == null) ? 0 : tamanhos.hashCode());
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Categoria other = (Categoria) obj;
		if (calzone != other.calzone)
			return false;
		if (id != other.id)
			return false;
		if (nome == null) {
			if (other.nome != null)
				return false;
		} else if (!nome.equals(other.nome))
			return false;
		if (produtosVariaveis == null) {
			if (other.produtosVariaveis != null)
				return false;
		} else if (!produtosVariaveis.equals(other.produtosVariaveis))
			return false;
		if (status != other.status)
			return false;
		if (tamanhos == null) {
			if (other.tamanhos != null)
				return false;
		} else if (!tamanhos.equals(other.tamanhos))
			return false;
		return true;
	}
}
@Entity
@Table(name = "tamanho_pizza")
public class Tamanho{

	private int id;
	private String nome;
	private int pedacos;
	private int quantidadeSabores;
	private int status;
	private List<CategoriaTamanho> categorias;

	public Tamanho(){
	}
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public int getPedacos() {
		return pedacos;
	}

	public void setPedacos(int pedacos) {
		this.pedacos = pedacos;
	}

	@Column(name="qtd_sabores")
	public int getQuantidadeSabores() {
		return quantidadeSabores;
	}

	public void setQuantidadeSabores(int quantidadeSabores) {
		this.quantidadeSabores = quantidadeSabores;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	@SuppressWarnings("deprecation")
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.tamanho",cascade = 
	{CascadeType.PERSIST, CascadeType.MERGE})
	@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
	public List<CategoriaTamanho> getCategorias() {
		return categorias;
	}

	public void setCategorias(List<CategoriaTamanho> categorias) {
		this.categorias = categorias;
	}
}
@Entity
@Table(name = "categoriaTamanho")
@AssociationOverrides({
		@AssociationOverride(name = "id.categoria", joinColumns = @JoinColumn(name = "id_categoria")),
		@AssociationOverride(name = "id.tamanho", joinColumns = @JoinColumn(name = "id_tamanho")) })
public class CategoriaTamanho {

	private CategoriaTamanhoID id = new CategoriaTamanhoID();
	private double precoPizza;

	@EmbeddedId
	private CategoriaTamanhoID getId() {
		return id;
	}
	
	@SuppressWarnings("unused")
	private void setId(CategoriaTamanhoID id){
		this.id = id;
	}
	
	@Transient
	public Categoria getCategoria(){
		return getId().getCategoria();
	}
	
	public void setCategoria(Categoria categoria){
		getId().setCategoria(categoria);
	}
	
	@Transient
	public Tamanho getTamanho(){
		return getId().getTamanho();
	}
	
	public void setTamanho(Tamanho tamanho){
		getId().setTamanho(tamanho);
	}

	@Column(name="preco_pizza")
	public double getPrecoPizza() {
		return precoPizza;
	}

	public void setPrecoPizza(double precoPizza) {
		this.precoPizza = precoPizza;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		long temp;
		temp = Double.doubleToLongBits(precoPizza);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CategoriaTamanho other = (CategoriaTamanho) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (Double.doubleToLongBits(precoPizza) != Double
				.doubleToLongBits(other.precoPizza))
			return false;
		return true;
	}

	
}
@Embeddable
public class CategoriaTamanhoID implements Serializable{
	
	private static final long serialVersionUID = -8458934953153980852L;
	private Tamanho tamanho;
	private Categoria categoria;
	
	@ManyToOne
	public Tamanho getTamanho() {
		return tamanho;
	}
	
	public void setTamanho(Tamanho tamanho) {
		this.tamanho = tamanho;
	}
	
	@ManyToOne
	public Categoria getCategoria() {
		return categoria;
	}
	
	public void setCategoria(Categoria categoria) {
		this.categoria = categoria;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((categoria == null) ? 0 : categoria.hashCode());
		result = prime * result + ((tamanho == null) ? 0 : tamanho.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CategoriaTamanhoID other = (CategoriaTamanhoID) obj;
		if (categoria == null) {
			if (other.categoria != null)
				return false;
		} else if (!categoria.equals(other.categoria))
			return false;
		if (tamanho == null) {
			if (other.tamanho != null)
				return false;
		} else if (!tamanho.equals(other.tamanho))
			return false;
		return true;
	}
	
	
}