JPA - Mapeamento @ManyToOne onde a entidade não existe ainda

Não estou conseguindo realizar este mapeamento quando as entidades da parte Many ainda não existem, vou postar meu código pra ser mais fácil o entendimento:

public class Categoria {
    @ManyToOne
    private List<PontoInteresse> pi;
}

Eu vou realizar primeiro a persistência de uma Categoria e em um outro momento irei realizar a persistência dos Pontos de Interesse, como configuro isso no JPA?

Cara, o lado que tem a lista, é o lado *ToMany do relacionamento.

Fiacaria assim então:

    public class Categoria {  
        @OneToMany  
        private List<PontoInteresse> pi;  
    }  
//Uma Categoria pode ter vários PontoInteresse.

A classe PontoInteresse, fica assim?

public class PontoInteresse {
    @OneToOne
    private Categoria categoria;
}
//Um PontoInteresse pode pertencer a somente uma Categoria.

Mas e quanto ao fato de eu salvar primeiro a Categoria e depois os Pontos de Interesse?

Você precisa setar a sua Categoria persistida como atributo de cada PontoInteresse.

[code]Categoria categoria = new Categoria();
entityManager.persist(categoria);

PontoInteresse ponto = new PontoInteresse();
ponto.setCategoria(categoria);
entityManager.persist(ponto);[/code]

A idéia é basicamente essa.

Então, eu não tenho um PontoInteresse quando vou persistir a Categoria, isso que preciso fazer, sacou?
Como persistir a Categoria primeiro, e num segundo momento persistir um PontoInteresse e vincular a uma determinada Categoria.

[code]Categoria categoria = entityManager.find(Categoria.class, 1); //Supondo que a PK da sua categoria tem valor 1

PontoInteresse ponto = new PontoInteresse();
ponto.setCategoria(categoria);
entityManager.persist(ponto); [/code]

Tem outras maneiras de fazer, mais performáticas inclusive. Mas assim funciona.

O digaoneves realmente explicou tudo.

Aqui tem um post que poderá te ajudar: @OneToMany e @ManyToOne Unidirecional e Bidirecional.

Entendi. No caso quando eu for cadastrar um PontoInteresse, eu tenho na tela um SelectOneMenu(PrimeFaces), o qual estou populando a partir do ManagedBean CategoriaMB. Qual a melhor forma pra eu conseguir setar dentro do PontoInteresse a Categoria selecionada no SelectOneMenu? Tem como pegar o value do SelectOneMenu e setar Categoria direto dentro do PontoInteresse?

Outra coisa, quando eu persistir o Categoria sem ter nenhum objeto PontoInteresse inserido em list vai ocorrer erro ou salva normal?

Basta enviar para o select uma lista de Categoria. Quando se utilizar uma classe própria em um select, será necessário utilizar um converter. Aqui tem um exemplo: JSF: Converter e Bean Auto Complete.

[quote]quando eu persistir o Categoria sem ter nenhum objeto PontoInteresse inserido em list vai ocorrer erro ou salva normal?[/quote]Tenta uai. :stuck_out_tongue: :lol: :lol: :lol:

Obrigado pela ajuda galera, mas agora estou com dificuldades em fazer o Converter rodar, quando tento executar o método:

ele entra em looping, não sei o que posso estar fazendo errado. Segue meu código para análise:

telaAdicionarPontoInteresse

					<p:selectOneMenu id="categoria" value="#{pontoInteresseMB.pontoInteresse.categoriaServico}" effect="fade">  
						<f:selectItem itemLabel="Selecione" itemValue=""  />  
						<f:selectItems value="#{categoriaServicoMB.categorias}"
									   var="categoria"
									   itemLabel="#{categoria.nomeCategoria}"
									   itemValue="#{categoria.nomeCategoria}"/>
						<f:converter converterId="categoriaServicoConverter"/>
					</p:selectOneMenu>

CategoriaServicoConverter

package com.Converter;

import com.modelo.managedBean.CategoriaServicoMB;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(value="categoriaServicoConverter")
public class CategoriaServicoConverter implements Converter {
 
    @Override
    public Object getAsObject(FacesContext arg0, UIComponent arg1, String key) {
        FacesContext context = FacesContext.getCurrentInstance();
        CategoriaServicoMB categoriaServicoMB = (CategoriaServicoMB) context.getELContext().getELResolver().getValue(context.getELContext(), null, "categoriaServicoMB");
 
        return categoriaServicoMB.getCategoriaServicoPorNome(key);
    }
 
    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
        return arg2.toString();
    }
}

CategoriaServicoMB

package com.modelo.managedBean;

import com.modelo.bean.CategoriaServico;
import com.modelo.dao.CategoriaServicoDAO;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class CategoriaServicoMB {

	private Integer id;
	private CategoriaServicoDAO categoriaDAO = new CategoriaServicoDAO();
	private CategoriaServico categoriaServico = new CategoriaServico();
	private List<CategoriaServico> categorias = new ArrayList<CategoriaServico>();

	// GETTER / SETTER
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
		if (id != null) {
			categoriaServico = categoriaDAO.recuperarCategoriasServico(this.getId());
		}
	}

	public CategoriaServico getCategoriaServico() {
		return categoriaServico;
	}

	public void setCategoriaServico(CategoriaServico categoriaServico) {
		this.categoriaServico = categoriaServico;
	}

	public List<CategoriaServico> getCategorias() {
		categorias = categoriaDAO.listarCategoriaServico();
		return categorias;
	}

	// REGRAS DE NEGÓCIO
	public String salvar() {
		if (categoriaDAO.inserirCategoriaServico(categoriaServico)) {
			return "sucessoOperacao";
		} else {
			return "falhaOperacao";
		}
	}

	public String excluir() {
		categoriaServico = categoriaDAO.recuperarCategoriasServico(categoriaServico.getIdCategoriaServico());
		if (categoriaDAO.excluirCategoriaServico(categoriaServico)) {
			return "sucessoOperacao";
		} else {
			return "falhaOperacao";
		}
	}

	public String atualizar() {
		if (categoriaDAO.atualizarCategoriaServico(categoriaServico)) {
			return "sucessoOperacao";
		} else {
			return "falhaOperacao";
		}
	}

	public CategoriaServico getCategoriaServicoPorNome(String nome) {
		this.getCategorias();
		for (CategoriaServico categoria : categorias) {
			if (categoria.getNomeCategoria().equals(nome)) {
				return categorias.get(categoria.getIdCategoriaServico());
			}
		}
		return null;
	}
}

Retire a linha FacesContext.getCurrentInstance(); pois voce ja recebe o faces context como parametro no converter

Se eu retirar esta linha não consigo compilar pois a variável context não está inicializada, ai se eu seto ela como null, nem entra na linha de baixo…CategoriaServicoMB categoriaServicoMB = (CategoriaServicoMB) …

[code]@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String key) {
FacesContext context = FacesContext.getCurrentInstance();
CategoriaServicoMB categoriaServicoMB = (CategoriaServicoMB) context.getELContext().getELResolver().getValue(context.getELContext(), null, “categoriaServicoMB”);

return categoriaServicoMB.getCategoriaServicoPorNome(key);  

}[/code]

Olhe os 3 parâmetros que você recebe no método, o primeiro, é a instância do FacesContext, o segundo é o componente associado ao converter, e o terceiro, a String em si.
você não precisa pegar novamente a instância do faces context, porque ela ja é enviada a você como parâmetro, seu arg0.

Muito obrigado cara, nem acredito que funcionou =D
Agora, gostaria de mais um ajuste, sempre que for excluir uma CategoriaServico e exister um PontoInteresse vinculado a ela não deixar, só posso excluir a CategoriaServico depois que excluir todos os PontoInteresse vinculados a ela. Sabe como?