Maneira preferível de escrever aplicativos de banco de dados Delphi com transações e componentes com reconhecimento de dados

StackOverflow https://stackoverflow.com/questions/3833432

Pergunta

Qual é a maneira preferível de escrever aplicativos de banco de dados Delphi usando transações e também componentes com reconhecimento de dados?

Eu tenho que escrever um aplicativo cliente que acessa as tabelas Innodb e faça alguns tipos de coisas mestres dentro de transações. Depois de fazer algumas pesquisas sobre transações (do ponto de vista geral), humildemente concluo que os componentes sem reconhecimento de dados e SQL codificados à mão seriam a "correspondência perfeita" das transações; Mas os componentes com reconhecimento de dados não seriam. Eles não parecem ser feitos um para o outro.

Eu tenho a necessidade real de usar transações, mas, por outro lado, eu não poderia simplesmente jogar os componentes com reconhecimento de dados, porque eles simplificaram bastante as coisas.

Alguém poderia me esclarecer? Eu tenho pesquisado no Google, mas não encontrei nenhuma resposta útil. Talvez porque meu inglês não seja bom o suficiente para que minhas palavras -chave sejam limitadas.

BTW, estou usando o Delphi 7 e atualmente avaliando o UNIDAC como a biblioteca de acesso a dados.

Obrigada.

EDITAR

Exemplo para descrever um aspecto da minha pergunta:

Imagine uma forma com 2 dBgrids nele. A primeira grade é o MasterGrid e acima dela são esses botões: Adicionar, editar e excluir. A segunda grade é detalhada. Se o usuário clicar em Adicionar, será assim:

  • Connection.startTransaction
  • Master.Append então Master.Post Then Master.edit (então o conjunto de dados mestre tem a chave primária do AutoinCrement, e é editável agora)
  • Mostre o formulário de edição modalmente, no qual o usuário preenche os registros mestre e também adicione alguns registros detalhados usando outro formulário.
  • Se o usuário clicar em OK, o aplicativo faria Master.Post e Connection.Commit. Se o usuário clicar em cancelar, o aplicativo fará o Connection.Rollback.

Sei que as transações devem ser o mais curtas possível, mas você pode ver acima que a transação é tão curta quanto a velocidade do usuário preenchendo o formulário.

Se eu estivesse usando componentes sem reconhecimento de dados, faria SQLs de inserção personalizada com base na entrada do usuário e executaria o SQL entre o StartTransaction e o Commit. Para que eu possa obter uma transação muito curta.

Editar 2

Agradeço a todos por sua participação. Escolho a resposta do VCLEVENER, porque é a solução mais próxima da minha necessidade atual.

Foi útil?

Solução

Outros mencionaram o uso de uma combinação de DataSeTProvider e ClientDataSet para ter uma atualização em lote, mas, no caso de usar componentes ADO ou UNIDAC, você não precisa da camada extra de DataSeTProvider + ClientDataSet, porque as atualizações de lote de suporte ADO e UNIDAC.

Por ALVOROÇO, o que você deve fazer é definir LockType do seu conjunto de dados para ltbatchOtimistic. Por Unidac, você deve definir CacheUpdate propriedade para Verdadeiro.

Essa alteração faz seu conjunto de dados para armazenar em cache todas as alterações que você faz em seu conjunto de registros na memória e envie-as para o banco de dados somente quando você liga UpdateBatch Método (ADO) ou APLICARUPDATES Método (UNIDAC).

Agora, o que você deve fazer é permitir que seu usuário insira/edite um registro no conjunto de dados mestre e quaisquer registros que ele/ela deseje no conjunto de dados de detalhes usando os componentes com reconhecimento de dados que desejar. Todas as mudanças seriam armazenadas em cache. Quando o seu usuário estiver pronto, você pode iniciar uma nova transação e primeiro chamada updateBatch (ou aplicarpdate no caso da UNIDAC) para o conjunto de dados mestre e, em seguida, para o conjunto de dados de detalhes e, se tudo correr bem, comprometa a transação.

Isso tornará suas transações curtas sem a necessidade da camada extra do ClientDataset.

Cumprimentos

Outras dicas

Eu entendo sua pergunta, eu acho. Ao abrir um tadodataSet com por exemplo, 10 linhas de dados a serem editadas em um formulário, com componentes com reconhecimento de dados, há situações em que você deseja cache todas as alterações feitas em todas as 10 linhas (e possivelmente deleções e inserções) e cometê -lo como um lote. Você não pode abrir a transação na primeira alteração, pois isso bloquearia outros usuários alterando os mesmos dados. As transações devem ser o mais curtas possível.

O que faço no cenário esboçado é usar os seguintes componentes em uma cadeia:

Tadoconection >> tadodataset >> tdatasetProvider >> tclientDataSet >> tdatasource >> tdbedits etc.

Agora, todas as alterações são armazenadas em cache no tclientDataSet e você pode chamar seu método ApplyUpDates para publicar todas as alterações em uma transação rápida. Lembre-se de que também é possível usar vários tadodatasets e vários tclientDataSets para uma estrutura mestre-detail (-Detail-ETC) com conjuntos de dados aninhados. Todas as alterações mestres-detalhes também podem ser armazenadas em cache e aplicadas em um lote em uma transação. Veja a ajuda e os recursos em outros lugares para obter todos os detalhes sobre a implementação disso. No começo, não é fácil. Mas se você descobriu, é fácil e oferece muitas possibilidades. (Edição offline, examinando as mudanças antes de aplicá -las, etc.)

Para evitar a necessidade de realizar grandes transações que eu uso DataSetProviders e ClientDataSets (mesmo localmente).

Considere usar isso como uma espécie de cache e oferece o melhor dos dois mundos. Você pode usar controles com reconhecimento de dados para simplificar as coisas enquanto trabalha na interface do usuário. As ações do usuário sobre os conjuntos de dados são "registradas" pelos dados do cliente (tipo de cache do banco de dados).

Quando seu usuário estiver pronto para Salve  As alterações no banco de dados (por exemplo, os dados da fatura estão todos no lugar), você chama o APLICARUPDATES Método para o (s) conjunto (s).

No cenário mais simples, onde todos os conjuntos de dados estão no relacionamento mestre-detalhe (aninhado pelo provedor), o provedor inicia e comete/reverte a transação por si só, para que você esteja em uma situação de tudo ou nada automaticamente.

Se você tiver relacionamentos mais complexos, poderá ligar para o StartTransaction antes de começar a aplicar atualizações para cada conjunto de dados do ClientDataSet envolvido e, no final, a chamada de chamada ou reversão conforme necessário). A lógica para o provedor é se a conexão tiver uma transação ativa quando o ApplUpDates for chamado, não faz nada com a transação, mas simplesmente poste alterações no banco de dados, assumindo que você está no controle da transação.

Você precisa ler sobre o TclientDataSet e como lidar com o OnReCoCileError e experimentar a tecnologia antes de colocá -la em ambientes de produção, mas funciona muito, muito bem para mim.

Meus 2 centavos.

Você está absolutamente certo que um Escreva A transação deve ser o mais curta possível e não deve estar vivo o tempo todo enquanto um usuário preenche o formulário.

A solução geral, como já respondido, é usar uma camada intermediária (um clientDataSet). Mas o verdadeiro problema com o seu cenário é que você não pode obter um valor de autoincrement para a tabela mestre sem mestre. Escreva transação muito antes de ser realmente necessária.

Portanto, se você não quiser usar a camada intermediária e ainda usar componentes com reconhecimento de dados com curta Escreva Transações Você deve pensar em um banco de dados que suporta a obtenção de um valor de incrementado automaticamente sem executar o Insert (para a tabela mestre). O exemplo é Firebird O banco de dados e os componentes de acesso a dados do FIBPLUS para o Firebird suportam totalmente esse recurso.

As transações devem ser tão curtas quanto precisava. O problema é como diferentes bancos de dados lidam com o bloqueio. Os bancos de dados que executam apenas o bloqueio no nível da linha e podem retornar imediatamente de um bloqueio sem esperar têm muito menos probabilidade de impasse. Normalmente, as inserções são menos problemáticas (embora outro usuário não veja novas linhas até que seja comprometido, dependendo do nível de isolamento), as atualizações e exclusões são mais problemáticas. Cometer muitas vezes também pode ser "ruim". As alterações em cache e aplicá -las em uma única operações é outra possibilidade - mas você precisa lidar com problemas devido a outros usuários alterarem os registros. Não existe uma solução "melhor" - tudo depende das necessidades reais. Para alguns aplicativos (e alguns bancos de dados), mantendo o registro bloqueado, desde que estejam mudando, pois outros não podem. As atualizações de lote podem estar bem em alguns cenários e não em outras. Você deve selecionar o modelo que funciona melhor para o seu aplicativo e banco de dados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top