Erro em Constraint para Relacionamento Bidirecional [Resolvido] - ERRO EM CASCADE [Resolvido]

15 respostas
robertouba

Tarde galera!
Estou com um erro esquisito…

Tenho uma classe de Fornecedores, Produtos, e FornecedorProduto onde nessa tabela eu quero fazer um bidirecional, e contém várias informações…
Vamos as classes:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Item_Type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("0")
public class Item {
	@Id
	@GeneratedValue
	private Long id;


	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name = "Item_Provider", inverseJoinColumns = @JoinColumn(name = "id"), joinColumns = @JoinColumn(name = "item_id"))
	private List<ItemProvider> providerInfo;
@Entity
public class Provider {
	@Id
	@GeneratedValue
	private Long id;

	@ManyToMany
	@JoinTable(name = "Item_Provider", inverseJoinColumns = @JoinColumn(name = "id"), joinColumns = @JoinColumn(name = "provider_id"))
	private List<ItemProvider> item;
@Entity
@Table(name = "Item_Provider")
public class ItemProvider {
	@Id
	@GeneratedValue
	private Long id;

	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name = "Item_Provider", inverseJoinColumns = @JoinColumn(name = "provider_id"), joinColumns = @JoinColumn(name = "id"))
	private Provider provider;

	@ManyToMany(cascade = CascadeType.ALL)
	//@JoinTable(name = "Item_Provider", inverseJoinColumns = @JoinColumn(name = "item_id"), joinColumns = @JoinColumn(name = "id"))
	private Item item;

	@Column(length = 50)
	private String code;

	@Column(length = 80)
	private String name;

Bom, no começo na minha classe ItemProvider eu usei @ManyToOne, mas houve um erro na Chave Estrangeira, ele indexou o ID (PrimaryKey) com uma outra chave extrangeira…
Alguém sugere uma maneira mais fácil de resolver isso?

Valew Galera!

15 Respostas

drsmachado

Camarada, por gentileza, troque as tags quote por code, para facilitar a visibilidade do código.
Assim mais foristas irão dar atenção e responder seus tópicos.
Grato.

robertouba

nossa cara, fiz com tanta pressa que nem me toquei… sabe quando tu estás há mais de 4 horas tentando entender o problema… pois é! kkk

robertouba

Bom, estou colocando uma imagem explicativa! Mais tranquilo!
Entretanto, não posso ter bloqueio de chave, pois eu devo ter vários itens com mesmo pai e com mesmo filho.


Lucas_Cavalcanti

roberto, teoricamente o mais simples possível funciona pro seu caso:

@Entity
class Pai {

    @OneToMany(mappedBy="pai")
    List<Prole> proles;
}

@Entity
class Filho {
     @OneToMany(mappedBy="filho")
     List<Prole> proles;
}

@Entity
class Prole {
    @Id @GeneratedValue
    Long id;


    @ManyToOne
    Pai pai;

    @ManyToOne
    Filho filho;

    outras coisas
}

assim vc pode colocar qtas proles vc quiser, não importando qtos pais e filhos existem

vc só precisa desse id separado

robertouba

Realmente a criação do banco ficou perfeita como o Lucas disse, porém, salvando em cascata eu não consegui utilizando a seguinte maneira:

//Classe empresa
@Entity
public class Empresa extends PessoaJuridica {
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "pk.empresa")
	private List&lt;Conta&gt; contas = new ArrayList&lt;Conta&gt;();
//Aqui tenho a classe conta, que deve receber a empresa
@Entity
@Table(name = "Empresa_Conta")
public class Conta {

	@EmbeddedId
	private ContaPK pk;

	/**
	 * Use only for MySQL and PostGree database
	 */
	@DateTimeFormat(pattern = "dd/MM/yyyy")
	@Temporal(TemporalType.TIMESTAMP)
	@Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
	private Date dataCriacao = new Date();

	@NumberFormat(style = Style.CURRENCY)
	private float preco = 0;

	@NumberFormat(style = Style.CURRENCY)
	private float mensalidade = 0;

	private Integer status = 1;
//Aqui tenho a classe que gera a PK na tabela.
public class ContaPK implements Serializable {

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

	@ManyToOne(fetch = FetchType.EAGER, optional = false)
	private Empresa empresa;

	@ManyToOne(fetch = FetchType.EAGER, optional = false)
	private Sistema sistema;
@Livre
	@Post
	@Path("/register/")
	public void Registrar(Empresa empresa) {
		this.validator.validate(empresa);
		//Passando todos os parâmetros da empresa, recebendo a conta como empresa.conta[0]
		this.empresaDao.save(empresa);
		this.result.redirectTo(this).registrado();
	}
Lucas_Cavalcanti

primeiro: cuidado com o cascade… principalmente o ALL… se vc só vai usá-lo para persist, deixe PERSIST

segundo, mesmo que esteja o cascade, vc precisa setar o relacionamento do lado forte (o sem mapped by)

ou seja, não adianta só colocar a conta na lista, vc tem que fazer um conta.setEmpresa(empresa) também.

robertouba

Eu tentei colocar o SetEmpresa dentro da classe Conta, mas mesmo assim não deu certo.
Porém já tem o SetEmpresa no ContaPK.

Lucas_Cavalcanti

mas vc setou a empresa na pk da conta antes de salvar a empresa?

robertouba

Ah não, to fazendo tudo em cascade!

só estou passando empresa pro meu metodo, e queria salvar tudo, por isso nem criei a conta, mas vou criar então.

Lucas_Cavalcanti

tudo bem isso de vc querer salvar tudo…

mas fazer:

empresa.getContas().add(conta);
...
dao.salva(empresa)

não faz o relacionamento no banco, mesmo que esteja com cascade!

o que vc precisa fazer é o seguinte:

empresa.getContas().add(conta);
conta.setEmpresa(empresa); // ou getPk().setEmpresa()

dao.salva(empresa);
robertouba

Para finalizar: Então preciso primeiro persistir minha empresa, e depois setar as contas, ou não?

Exemplo:

empresaDao.save(empresa);
Empresa e = this.empresaDao.load(empresa.getId());
e.setContas(conta);
dao.update(empresa);

Pois o seguinte código me dá erro:

Conta conta = new Conta();
		conta.getPk().setEmpresa(empresa);
		conta.getPk().setSistema(this.sistemaDao.load(contas.get(0).getPk().getSistema().getId()));

		empresa.setContas(null);
		empresa.getContas().add(conta);
Lucas_Cavalcanti

não precisa… faça:

empresa.setContas(conta);

conta.setEmpresa(empresa);

empresaDao.save(empresa);

o relacionamento é bidirecional, tem que setar dos dois lados, senão não funciona!

robertouba

Tentei da seguinte maneira:

List&lt;Conta&gt; contas = empresa.getContas();

		Conta conta = new Conta();
		conta.getPk().setEmpresa(empresa);
		conta.getPk().setSistema(this.sistemaDao.load(contas.get(0).getPk().getSistema().getId()));

		empresa.setContas(null);
		empresa.getContas().add(conta);
//Erro gerna nesta linha
conta.getPk().setEmpresa(empresa);
Lucas_Cavalcanti

empresa.setContas(null) e depois empresa.getContas().qqercoisa vai dar nullpointer mesmo né :wink:

robertouba

fiquei com medo de duplicar minha conta, sendo que estou recebendo ela já, entende?
Mas eliminei isso… e o erro continuou, pois o erro estava no conta.getPk.setEmpresa(empresa);

consegui arrumar fazendo a seguinte linha:

Obrigado Lucas, como sempre tu eres muito atencioso, paciente principalmente.

Criado 21 de setembro de 2011
Ultima resposta 7 de out. de 2011
Respostas 15
Participantes 3