none
Problema ao gerar código automático pelo delphi RRS feed

  • Pergunta

  • Boa noite pessoal,

    Estou desenvolvendo uma aplicação em Delphi com SQL Server 2008 Enterprise. Esse sistema irá gerenciar todo o controle de provas de uma escola.

    Preciso Armazenar em uma tabela todas as questões que o aluno fez em cada prova, nesse caso são 10 questões. Na tabela tenho um campo chamado cod_prova que deverá se repetir 10 vezes armazenando cada questão que o aluno fez. ex.:

     
    cod_prova 1 - quest_codigo 1
    cod_prova 1 - quest_codigo 2
    cod_prova 1 - quest_codigo 3
    cod_prova 1 - quest_codigo 4
    cod_prova 1 - quest_codigo 5
    cod_prova 1 - quest_codigo 6
    cod_prova 1 - quest_codigo 7
    cod_prova 1 - quest_codigo 8
    cod_prova 1 - quest_codigo 9
    cod_prova 1 - quest_codigo 10

    cod_prova 2 - quest_codigo 1
    cod_prova 2 - quest_codigo 2
    cod_prova 2 - quest_codigo 3

    e assim por diante...

    Não coloquei o campo cod_prova como Primary key, porque ele deverá se repetir a cada prova e deverá gravar 10 registros, ou seja, as 10 questões que o aluno fez.

    No delphi estou utilizando componentes AdoQuery para fazer a ligação com o banco. Tenho um Query que faz a ligação direta com a tabela no banco e um segundo somente para pegar o último registro da tabela.

    Assim, quando chamo o formulário em que o aluno deverá responder as questões, eu abro o segundo query mando ele para o último registro da tabela, jogo esse conteúdo em uma variável, e depois incremento ela em 1, assim se o último código for 2, a variavel recebe 2 e acrescenta 1 passando a valer 3.

    Código que faz os passos citados acima:

    var
       ultiCodProva1, ultiCodProva2:integer;
    begin
       tblAuxCodProva.Open;
       tblAuxCodProva.Last;
       ultiCodProva1:=tblAuxCodProvacod_prova.Value;
       ultiCodProva2:=ultiCodProva1+1;
       tblAuxCodProva.Close;
       lblCodProva.Caption:=IntToStr(ultiCodProva2);

    Depois jogo o conteúdo dessa variável em um Label. Cada vez que o aluno clica no botão avançar, ele grava o código, o nome do aluno, e as outras informções em uma tabela virtual. Quando chega no Décimo registro, ele chama o formulário de resultado e um botão finalizar. Ao clicar no botão finalizar, ele pega os dez registros da tabela virtual e grava na Tabela real do banco.

    Ele faz isso perfeitamente, porém quando realizo umas 20 provas, ele não incrementa mais a variável, ou seja, quando chega no cod_prova 20, ele deveria ir para o 21, mas isso não está acontecendo, fica sempre repetindo o código 20.

    Apaguei a tabela e crei de novo, depois de executar o programa, ele foi até a prova 42 sem repetir, depois começou a repetir o código 42 de novo. Utilizo esse mesmo método em outras tabelas e funciona perfeitamente.  

    obs:
    O campo na tabela está com Inteiro. 

    Há algum problema em repetir o mesmo código várias vezes? pois nas outras tabelas não estou repetindo o código assim.

    Pessoal se algém tiver alguma dica do que pode ser ficarei muito grato

    Desde já meus agradecimentos!!!

    Alessandro 


    terça-feira, 14 de fevereiro de 2012 23:32

Respostas

  • Alessandro,

    A indicação do Roberto é o que temos de melhor para o seu caso eu imagino, talvez você possa somente distribuir em tabelas diferenciadas;

    Criaria duas tabelas , na da propria prova, você deixa o codprova como IDENTITY, e grava multiplos registros na tabela Questoes;

    TabelaProva
    CodProva(PK identity), data

    TableaQuestoes
    Codquestao(Identity), CodProva (FK)

    Caso você precise limitar o CodQuestao até 10 para cada CodProva, então você pode fazer esse incremento na app deixando somente o incremento da prova por conta do SQL Server uma vez que a quantidade de provas será ilimitado, correto?

    Abraços,


    Marcos Leandro Rosa

    terça-feira, 21 de fevereiro de 2012 20:12

Todas as Respostas

  • Alessandro,

    Se a sua dúvida é somente em repetir o valor, não vejo problemas, agora isso vai depender em muito da sua regra de negócio.

    Em relação ao incremento que você esta se referindo, acredito que seja alguma falha no seu código. Tente fazer uma análise.


    Pedro Antonio Galvão Junior [MVP | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | SorBR.Net | Professor Universitário | MSIT.com]

    quarta-feira, 15 de fevereiro de 2012 11:10
  • Junior, muito obrigado pela atenção.

    Como eu também havia imaginado, o erro estava realmente no meu código.

    Mudei o código do Query que pega o último registro e deu certo.
    Fiz da seguinte maneira:

    select top 1 cod_prova from provas_detalhadas order by cod_prova desc

    dessa forma ele ordena a tabela de forma decrescente por código e seleciona apenas o último registro..

    depois somente incremento a variável.

    Agora só me surgiu um outro problema, quando dois alunos iniciarem a prova ao mesmo tempo, ele vai gerar o mesmo código para as duas provas, terei que rever meu código, acrescentar uma nova rotina antes de gravar os registros.

    obrigado!


    quinta-feira, 16 de fevereiro de 2012 00:56
  • Afantonio,

          Controlar o código que será inserido na base de dados através da aplicação não é uma boa alternativa para nenhum banco de dados, seja ele SQL Server ou concorrente, justamente porque você pode ter duas pessoas inserindo registros ao mesmo tempo.

          Há duas alternativas no seu caso:

           - Ser mais restritivo no momento de ler os dados, aumentando o seu nível de isolamento e controle de concorrência. Mas, como nada vem de graça, há um preço a pagar. Esse preço é alto e se chama bloqueio (locks) e ele pode afetar a performance da sua aplicação como um todo, pois você teria que aguardar que o primeiro aluno terminasse a transação na base para que um outro iniciasse uma nova transação. se isso for bem planejado na sua aplicação, você não deve ter problemas, mas, precisa analisar bem o caso. Veja maiores informaçoes sobre isso no Books Online sobre SET TRANSACTION ISOLATION LEVEL e Managing Concurrent Data Access.

            - Ao invés de controlar o código manualmente pela aplicação, tente utilizar um tipo de dado de autonumeração utilizando a propriedade IDENTITY. Acho esse tipo de abordagem mais adequado no seu caso, mas, claro, disso dependeria uma avaliação do seu código. Como você ainda está desenvolvendo a aplicação, acho que seria interessante reavaliar isso.

          Espero ter ajudado. 


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008


    segunda-feira, 20 de fevereiro de 2012 02:58
    Moderador
  • Roberto

    Eu pensei nessa possibilidade também, mas como citei acima, preciso repetir o mesmo código 10 vezes, sendo assim não posso utilizar o campo como auto-incremento. Estou criando uma rotina que antes de gravar os dados no banco, incrementa novamente o código, caso ele seja igual ao último da tabela. Por exemplo: se dois alunos iniciarem a prova ao mesmo tempo, o código das duas provas serão o mesmo. Então quando ele vai gravar no banco, a rotina verifica se o código é igual ao último da tabela, em caso afirmativo ele incrementa novamente o código da prova.

    a principio deu certo, mas ainda estou testando.

    obrigado pela atenção!!

    ___________________
    Alessandro F. Antônio


    segunda-feira, 20 de fevereiro de 2012 10:36
  • Alessandro,

    A indicação do Roberto é o que temos de melhor para o seu caso eu imagino, talvez você possa somente distribuir em tabelas diferenciadas;

    Criaria duas tabelas , na da propria prova, você deixa o codprova como IDENTITY, e grava multiplos registros na tabela Questoes;

    TabelaProva
    CodProva(PK identity), data

    TableaQuestoes
    Codquestao(Identity), CodProva (FK)

    Caso você precise limitar o CodQuestao até 10 para cada CodProva, então você pode fazer esse incremento na app deixando somente o incremento da prova por conta do SQL Server uma vez que a quantidade de provas será ilimitado, correto?

    Abraços,


    Marcos Leandro Rosa

    terça-feira, 21 de fevereiro de 2012 20:12
  • Marcos

    Muito obrigado, passei quase um dia tentado implementar uma rotina que tinha criado aqui para, antes de gravar os dados, verificar novamente se o código era igual ao último da tabela e, se fosse incrementar novamente, estava dando erros e mais erros, porque estou trabalhando com tabelas virtuais. Quando o código era igual ele incrementava, mas não gravava os dez registros que preciso.

    Bem então ontem à tarde resolvi dar mais uma passado pelo MSDN pra ver se alguém mais havia postado resposta e vi sua resposta. Como já estava meio stressado ontem rsrs, acabei deixando pra hoje. Fiz o que você sugeriu e deu certo. Diminui umas 30 linhas de código do meu aplicativo.

    Criei uma tabela como você sugeriu com um campo CodProva(PK identity), agora quando o aluno inicia a prova, eu abro a tabela, gravo um novo registro, depois pego esse código e jogo em label e depois apenas passo para a tabela virtual. Dessa forma nunca vai ter o problema do código se repetir, pois se dois ou mais alunos iniciarem a prova, o banco sempre vai criar um novo registro para cada prova.

    Muito obrigado

    abraços,

                                                            _______________________
                                                             Alessandro F. Antônio

                                                           

    quarta-feira, 22 de fevereiro de 2012 10:47
  • Que Bom que resolveu Alessandro! - Abraços,

    Marcos Leandro Rosa

    domingo, 26 de fevereiro de 2012 02:34