Duplicação de Primary Key

Java

27/02/2013

Fala galera, estava procurando um tópico sobre este problema, achei, mais o cara conseguiu resolver, mais não postou a resolução, o meu eh bem parecido com o dele.. estou fazendo uma aplicação em java, e estou com problemas em chave duplicada, ou seja, esse erro --> Duplicate entry '18' for key 'PRIMARY' 18, eh a id que está tentando inserir dois tipos de produtos ao mesmo tempo, fala que a venda foi cadastrada com sucesso, mais gera essa exceção..

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '18' for key 'PRIMARY'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)





O meu código da minha classe Vendas:





public class VendasControl {

PreparedStatement pst;
ResultSet rs;

String cadastraVenda = "INSERT INTO VENDAS (ID_VENDAS, ID_PRODUTOS, ID_ALUNOS, DATA_VENDAS, QUANTIDADE) "
+ " VALUES (?,?,?,?,?)";


String buscaUltimoCodigo = "SELECT MAX(ID_VENDAS) AS ID_VENDAS FROM VENDAS";


public VendasControl(){

}

public int buscarCodigoUltimaVenda(){
try{
ConexaoBD bd = new ConexaoBD();
pst = (PreparedStatement) bd.conectar().prepareStatement(buscaUltimoCodigo);
rs = pst.executeQuery();
if (rs.last()){
return rs.getInt("id_vendas");
}
bd.desconectar();
} catch (SQLException ex){
ex.printStackTrace();
}
return 0;
}

public void CadastrarVenda(VendasBean venda){

try{
ConexaoBD bd = new ConexaoBD();
pst = (PreparedStatement) bd.conectar().prepareStatement(cadastraVenda);
pst.setInt(1, venda.getId());
pst.setInt(2, venda.getIdProduto());
pst.setInt(3, venda.getIdAluno());
pst.setDate(4, venda.getDataVenda());
pst.setInt(5, venda.getQuantidade());
pst.executeUpdate();
bd.desconectar();
}catch (SQLException ex){
ex.printStackTrace();
}

}

}


Código que cadastra a venda:

private void cadastrarVenda(){
if(venda.size() == 0){
JOptionPane.showMessageDialog(this, "Inclua pelo menos um produto!");

}else{
try{
VendasControl vc = new VendasControl();
SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd"); //formata o campo para datas
java.util.Date d = new java.util.Date();
Date data = Date.valueOf(formato.format(d)); //data da venda
int codigo = vc.buscarCodigoUltimaVenda() + 1;
for (int i = 0; i < venda.size(); i++){
venda.get(i).setIdAluno(alunos.get(cbAlunos.getSelectedIndex()).getId());
venda.get(i).setDataVenda(data);
venda.get(i).setId(codigo);
vc.CadastrarVenda(venda.get(i));
}
JOptionPane.showMessageDialog(this, "Venda cadastrada com sucesso!");
}catch (Exception ex){
JOptionPane.showMessageDialog(this, "Erro ao cadastrar Venda!");
}
}
}


Aqui a imagem do que eu to falando !

[url]http://img171.imageshack.us/img171/913/print6lu.png[/url]

Quando eu clico em finalizar, é quando gera esse erro que eu falei acima !
Obs: Não importa o produto, pode ser de nome diferente, id diferente, se eh dois ou mais, da esse erro, agora se for um produto, nem gera erro e vai de booa !

Agradeço desde já quem puder me ajudar ! Obrigado e até mais :)
Vinicius Gomes

Vinicius Gomes

Curtidas 0

Respostas

Danilo Gomes

Danilo Gomes

27/02/2013

Cara, é possível usar um campo auto increment no ID_VENDAS?
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Outra coisa, já tentou debugar e ver se os valores das variáveis estão de acordo com o esperado?
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Cara, abstraindo as perguntas acima, existe um erro de lógica mesmo.


int codigo = vc.buscarCodigoUltimaVenda() + 1; // O MESMO ID SERÁ UTILIZADO NO FOR ABAIXO
for (int i = 0; i < venda.size(); i++){
venda.get(i).setIdAluno(alunos.get(cbAlunos.getSelectedIndex()).getId());
venda.get(i).setDataVenda(data);
venda.get(i).setId(codigo);
vc.CadastrarVenda(venda.get(i));
}



Veja que está utilizando o mesmo ID dentro do FOR, teria que repetir essa chamada no FOR também.
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

como assim repetir essa chamada no for !? não entendi !
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Não faria muito sentido né? rs

Então, qual a chave primária desta sua tabela? É o ID_VENDAS? Apenas ele?
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Minhas sugestões iniciais foram equivocadas porque, pelo que entendi, esta tabela é um relacionamento.

O que está acontecendo, imagino eu, é que a chave primária refere-se apenas ao ID_VENDAS.
Quando vai alocar um segundo produto utiliza (logicamente) o mesmo ID_VENDAS, violando a constraint.

Nesse caso, pode modificar a chave primária para que seja composta por outros IDS.

A chave pode ser {ID_VENDAS E ID_PRODUTOS}.

Dessa forma pode cadastrar mais de um produto para uma mesma venda.
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

Então me ajuda aqe, isso qe vce falou por ultimo fez sentido, mais é qe minha lógica não está muito boa..

essa é minha tabela vendas

create table vendas(

id_vendas int default null,
id_produtos int (50) default null,
id_alunos int (25) default null,
Data_vendas DATE default null,
quantidade int (10) default null,
primary key (id_vendas)
);
ALTER TABLE `vendas` ADD CONSTRAINT `fk_id_produtos`
FOREIGN KEY ( `id_produtos` )
REFERENCES `produtos` (`id_produto`) ;

ALTER TABLE `vendas` ADD CONSTRAINT `fk_id_alunos`
FOREIGN KEY ( `id_alunos` )
REFERENCES `alunos` (`id`) ;

ALTER TABLE vendas MODIFY id_vendas int NULL AUTO_INCREMENT;

GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

E como eu modificaria a chave primária para que seja composta por outros IDS ?
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Primeiro tem que remover o status de primary key de ID_VENDAS

Para remover a chave primária existe, não tenho certeza, mas acredito que seja:
ALTER TABLE tabela DROP PRIMARY KEY; 


Depois deve-se fazer algo do gênero:
ALTER TABLE  nomedatabela ADD CONSTRAINT PRIMARY KEY (campo1, campo2, ... campo N);


GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Se puder recriar a tabela é ainda mais fácil:

create table vendas(

id_vendas int default null,
id_produtos int (50) default null,
id_alunos int (25) default null,
Data_vendas DATE default null,
quantidade int (10) default null,
primary key (id_vendas, id_produtos)
);
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

Me passa seu email pra gente conversar melhor, se você puder, é claro !

Desde já agradeço a sua ajuda, e mais tarde eu testo o que vcê falou !

Abraçoo, té mais !
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

Minha ultima duvida !
Eu vou deixar o id_produtos como chave estrangeira tbm ? ou isso não é possivel ?

abrass
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Você DEVE deixar como chave estrangeira também para manter a integridade.

Qualquer coisa pode postar aí no fórum que a gente ajuda.
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Olhando agora como o tópico desenvolveu-se, faria mais sentido ficar lá no MySQL né? rs
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

A id_vendas não tinha que ser auto increment ? e a id_produtos ?

Pode colocar la no forum de MySQL sim, mais nem sei como qe coloca ! hsuahsua
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Nesse teu caso id_vendas não poderá ser auto increment, não para este caso, esta estrutura.

Se for autoincrement nunca vai conseguir associar dois produtos a uma mesma venda, seria necessária outra tabela (que não faria muito sentido aqui).

Conseguiu definir a chave composta? Creio que apenas isto resolverá seu problema.
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

Resolveu sim meu amigo ! Mais tem um porém, se eu colocar mais de um produto com mesmo id, da erro, ai gera erro na id_produtos.. olha >> Duplicate entry '13-30' for key 'PRIMARY'

O que eu tava pensando, é não deixar o cliente inserir mais de um produto com o mesmo nome, ou seja, com a mesma id..

entendeu !?
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013


o código que inclui o produto é esse:

 private void incluirProduto(){
        if (verificarQuantidade()){
           VendasBean vb = new VendasBean();
           vb.setIdProduto(produtos.get(cbProdutos.getSelectedIndex()).getId());
           vb.setQuantidade(Integer.parseInt(String.valueOf(ftfQuantidade.getValue())));
           venda.add(vb); 
           String produto = produtos.get(cbProdutos.getSelectedIndex()).getNome(); 
           String quantidade = String.valueOf(ftfQuantidade.getValue());
           String valor = String.valueOf(produtos.get(cbProdutos.getSelectedIndex()).getValor() * Integer.parseInt(quantidade));
           String [] campos = new String [] {produto, quantidade, valor};         
           tmVendas.addRow(campos); 
           total += Double.parseDouble(valor); 
           ftfTotal.setValue(total);
        
        }else{
            JOptionPane.showMessageDialog(this, "Quantidade inválida!");
            ftfQuantidade.requestFocus();
        }         
        
    }


porém não to sabendo definir uma lógica, que pra quando eu inserir um produto, ex: Whey, ai eu vou tentar inserir outro, de mesmo nome Whey, ele da uma msg, dizendo que não é possivel adc 2 ou mais produtos de mesmo nome pra um mesmo aluno, o produto tem que ser distinto !

Obrigado pela ajuda ai até agora ! Agradeço desde já ! Boa Tarde !
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Vinicius, imaginei que isso poderia acontecer em um caso remoto.

Como vi um campo de "quantidade" na venda, achei que nunca incluiria um mesmo produto, para um mesmo aluno em uma mesma venda, estou certo?

Não seria mais coerente inserir uma quantidade de produtos para uma venda?
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

como assim uma quantidade de produtos para uma venda?

quando vou faze a venda eu ja coloco a quantidade, por exemplo: incluo whey e na quantidade eu coloco qnts eu quiser e finalizo a venda da certo.. se eu colocar varios produtos distintos com quantas quantidades eu quiser, vai dar certo !

O que eu qeria, é que quando o cliente incluísse um produto, ai se por ventura ele ia e incluísse o mesmo produto, desse a mensagem pra ele falando que só pode o produto, se elee quiser mais, coloca na quantidade ! entende !?
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

tipo comparar um comboBox com um item da tabela entendeu !?

if (cbProdutos.getSelectedItem().toString() .....
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Entendi. Então fechamos o assunto banco de dados, correto?

//

Nessa parte de desktop não poderei ajudá-lo muito.

Mas acredito que conseguirá ver, simplesmente e sem dificuldades, se existe algum item duplicado na coleção enviada, basta implementar o equals do objeto.

Você pode, por exemplo, para saber se existem ítens duplicados, utilizar uma implementação de Set, como HashSet.

Se não me engano ele aceita uma collection como argumento de construção.

Dessa forma, passando sua collection para ele e comparando o size da coleção original com a do HashSet, saberá se existem ítens duplicados de modo simples e direto.

GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Se for necessário, pode fazer uso do Collections.frequency para saber o número de vezes em que aparece um elemento em uma coleção.

int occurrences = Collections.frequency(animals, "bat");
GOSTEI 0
Vinicius Gomes

Vinicius Gomes

27/02/2013

De banco de dados ta fechado. foi resolvido o problema, muuuito obrigado pela sua ajuda !

Essa parte ai, mais tarde eu tento, e depois posto e resultado aqui !

Muito obrigado, abraços !
GOSTEI 0
Danilo Gomes

Danilo Gomes

27/02/2013

Creio que não terá muitos problemas com o uso das collections.

Qualquer coisa posta aí.

[]'s
GOSTEI 0
José

José

27/02/2013

Como a dúvida aparentemente foi sanada, estou dando o tópico por concluído.
obrigado pela participação de todos !!!
GOSTEI 0
POSTAR