Bloquear registro firebird com TSimpleDataSet e Delphi 7
Como fazer para bloquear o registro que esta sendo colocado em modo de edição com o componente TSimpleDataSet da dbExpress no Delphi 7 acessando o Firebird 1.5.5.4926... tentei utilizar os comandos WITH LOCK e/ou FOR UPDATE WITH LOCK mas não obtive sucesso.
Por favor me ajudem.
Por favor me ajudem.
Neodir
Curtidas 0
Respostas
Marco Salles
28/08/2009
Eu acho que o configurando corretamente os Providers Flags dos Tfields
conjutamente com a Opção UpdateMode do TDataSetProvider, vc tera este controle
DataSetProvider >> upWhereAll *******PADRÃO
ProviderFlags dos Tfields > [pfInUpdate,pfInWhere] ******PADRÃO
O Padrão dos Providers Flags ( do DataSetProvider e dos Tfields ) ja tem esta
configuração de Bloqueio ( sem vc mexer sem nada )
Se dois usuários acessarem um Registro , o primeiro que efetiva Alterações
conseguira efetiva no Banco ... O Segundo obtera um erro que sera reportado
no Evento OnReconcileError
.. Talves vc não tenha percebido pq ao dar o ApplayUpdates não é reportado nenhum Erro.. Muito menos ao dar o Post ( ja que os dados estão na
Memória) ..
Mas em contrapartida o Registro Tb Não é Modificado .. Vc acha que foi alterado , mas não foi ( Verifique !!!!)
A pergunta talves seje outra ... Como reportar o Erro para o Usuário que ele
não pode Modificar o Registro naquele Momento , ja que o Registro foi
Modificado primeiro por Outro
Sugestão ...Faça uma pesquisa por Reconncile Error Dialog Aqui mesmo no
site e veja se isto pode te ajudar a informar ao usuário este Bloqueio
conjutamente com a Opção UpdateMode do TDataSetProvider, vc tera este controle
DataSetProvider >> upWhereAll *******PADRÃO
ProviderFlags dos Tfields > [pfInUpdate,pfInWhere] ******PADRÃO
O Padrão dos Providers Flags ( do DataSetProvider e dos Tfields ) ja tem esta
configuração de Bloqueio ( sem vc mexer sem nada )
Se dois usuários acessarem um Registro , o primeiro que efetiva Alterações
conseguira efetiva no Banco ... O Segundo obtera um erro que sera reportado
no Evento OnReconcileError
.. Talves vc não tenha percebido pq ao dar o ApplayUpdates não é reportado nenhum Erro.. Muito menos ao dar o Post ( ja que os dados estão na
Memória) ..
Mas em contrapartida o Registro Tb Não é Modificado .. Vc acha que foi alterado , mas não foi ( Verifique !!!!)
A pergunta talves seje outra ... Como reportar o Erro para o Usuário que ele
não pode Modificar o Registro naquele Momento , ja que o Registro foi
Modificado primeiro por Outro
Sugestão ...Faça uma pesquisa por Reconncile Error Dialog Aqui mesmo no
site e veja se isto pode te ajudar a informar ao usuário este Bloqueio
GOSTEI 0
Neodir
28/08/2009
Cara tem alguma forma de validar via try except sem exibir a tela do EReconcileError?
GOSTEI 0
Marco Salles
28/08/2009
Não é necessário exibir a tela... Mas vc pode modifica-la , altera-ra , segundo os seu gosto
A exceção é silenciosa , para usar um bloco Try Except vc deve forçar
uma exceção
Por exemplo
try
bla bla
cds.post;
except
//Não captura o erro .. Esta em memória
try
bla bla
cds.ApplayUpdates
except
//captura o erro porém não ira mostrar neste Bloco.. Vai mostrar no Evento
//OnEconcilleErro
try
bla bla
if cds.ApplayUpdates(0) > 0 then // Nenhum erro é tolerável parametro Zero
Raise Cria a Exceção ...
except
//captura o erro criado pela condição
Mas no Post de um registro vc não consegue , a não ser que a cada post
vc force um ApplayUpadtes , que depedendo da situação pode comprometer
a performance de seu aplicativo
Agora vc pode usar o EventoOnEconcileError e Tratar do seu modo a Exceção
lancada , sem ter que chamar o Formulario
Tente isto
procedure TForm1.SeuDataSet1ReconcileError(DataSet: TCustomClientDataSet;
E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
showmessage(e.Message); //
end;
ps) Ha outra tecnicas tb usando o DataSetProvider
A exceção é silenciosa , para usar um bloco Try Except vc deve forçar
uma exceção
Por exemplo
try
bla bla
cds.post;
except
//Não captura o erro .. Esta em memória
try
bla bla
cds.ApplayUpdates
except
//captura o erro porém não ira mostrar neste Bloco.. Vai mostrar no Evento
//OnEconcilleErro
try
bla bla
if cds.ApplayUpdates(0) > 0 then // Nenhum erro é tolerável parametro Zero
Raise Cria a Exceção ...
except
//captura o erro criado pela condição
Mas no Post de um registro vc não consegue , a não ser que a cada post
vc force um ApplayUpadtes , que depedendo da situação pode comprometer
a performance de seu aplicativo
Agora vc pode usar o EventoOnEconcileError e Tratar do seu modo a Exceção
lancada , sem ter que chamar o Formulario
Tente isto
procedure TForm1.SeuDataSet1ReconcileError(DataSet: TCustomClientDataSet;
E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
showmessage(e.Message); //
end;
ps) Ha outra tecnicas tb usando o DataSetProvider
GOSTEI 0
Osocram
28/08/2009
Existe algum movito de vc não querer usar o ReconcileError?
Pois o que o Marco Salles comentou esta correto.
E outra... o interessante de se usar o ReconcileError é que os exception do seu DataSet vai estar sempre no mesmo lugar.
Pois o que o Marco Salles comentou esta correto.
E outra... o interessante de se usar o ReconcileError é que os exception do seu DataSet vai estar sempre no mesmo lugar.
Cara tem alguma forma de validar via try except sem exibir a tela do EReconcileError?
GOSTEI 0
Neodir
28/08/2009
Não. Não há problema com o EReconcileError é que estou tentando contornar um outro erro que esta acontecendo... a situação é a seguinte:
Transação da operação:
procedure TBase.TransactionBase(myTable: TSimpleDataSet);
var
TD: TTransactionDesc;
begin
if not DmoPrincipal.SQLCBASE.InTransaction then begin
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
DmoPrincipal.SQLCBASE.StartTransaction(TD);
try
MyTable.ApplyUpdates(0);
DmoPrincipal.SQLCBASE.Commit(TD);
except
on E :Exception do begin
DmoPrincipal.SQLCBASE.Rollback(TD);
end;
end;
end;
end;
Evento EReconcileError:
if (Pos(´Record not found or changed by another user´, E.Message) > 0) then begin
Application.MessageBox(´Atenção!´+#13+´Não foi possível salvar as Alterações!´,´Sistema´,mb_ok+mb_iconerror);
DataSet.CancelUpdates;
Exit;
end;
após passar pelo evento:
Apresenta uma mensagem de Abstract Error... e se tento colocar um breakpoint para acompanhar passo a passo trava o delphi...
Transação da operação:
procedure TBase.TransactionBase(myTable: TSimpleDataSet);
var
TD: TTransactionDesc;
begin
if not DmoPrincipal.SQLCBASE.InTransaction then begin
TD.TransactionID := 1;
TD.IsolationLevel := xilREADCOMMITTED;
DmoPrincipal.SQLCBASE.StartTransaction(TD);
try
MyTable.ApplyUpdates(0);
DmoPrincipal.SQLCBASE.Commit(TD);
except
on E :Exception do begin
DmoPrincipal.SQLCBASE.Rollback(TD);
end;
end;
end;
end;
Evento EReconcileError:
if (Pos(´Record not found or changed by another user´, E.Message) > 0) then begin
Application.MessageBox(´Atenção!´+#13+´Não foi possível salvar as Alterações!´,´Sistema´,mb_ok+mb_iconerror);
DataSet.CancelUpdates;
Exit;
end;
após passar pelo evento:
Apresenta uma mensagem de Abstract Error... e se tento colocar um breakpoint para acompanhar passo a passo trava o delphi...
GOSTEI 0
Marco Salles
28/08/2009
O Porprio midas se encarrega das Transações na tecnologia DbExpress
Vc deve usar Transação explicita , qnd estiver executando Sql
(insert , Update ou Delete) .. Fora isto , não precisa se preocupar que
a Propria instrução ApplayUpdates irá persisitir ou não as Alterações
Mas vc pode testar no seu codigo o seguinte ;
Vc deve usar Transação explicita , qnd estiver executando Sql
(insert , Update ou Delete) .. Fora isto , não precisa se preocupar que
a Propria instrução ApplayUpdates irá persisitir ou não as Alterações
Mas vc pode testar no seu codigo o seguinte ;
procedure TBase.TransactionBase(myTable: TSimpleDataSet); var TD: TTransactionDesc; begin if not DmoPrincipal.SQLCBASE.InTransaction then begin TD.TransactionID := 1; TD.IsolationLevel := xilREADCOMMITTED; DmoPrincipal.SQLCBASE.StartTransaction(TD); if MyTable.ApplyUpdates(0) = 0 Then DmoPrincipal.SQLCBASE.Commit(TD) else DmoPrincipal.SQLCBASE.Rollback(TD); end;
Evento EReconcileError: if (Pos(´Record not found or changed by another user´, E.Message) > 0) then begin Application.MessageBox(´Atenção!´+#13+´Não foi possível salvar as Alterações!´,´Sistema´,mb_ok+mb_iconerror); end;
GOSTEI 0
Neodir
28/08/2009
Valeu pela ajuda pessoal com alguns ajustes no meu código consegui o resultado esperado ao comitar a transação...
[b:a68680d46a]Porém gostaria de saber ainda se há a possibilidade de verificar se o registro está sendo usado por outro usuário no momento de colocá-lo em edição?[/b:a68680d46a]
[b:a68680d46a]Porém gostaria de saber ainda se há a possibilidade de verificar se o registro está sendo usado por outro usuário no momento de colocá-lo em edição?[/b:a68680d46a]
GOSTEI 0
Marco Salles
28/08/2009
Não vale a pena vc se preocupar com isto.
É uma questão de Custo Benfecio.. Nesta situação na maior parte das
vezes vence o Custo.
Qauntas vezes durante o Dia terá este conflito e quantas veses não terá
Para verificar isto , mesmo na situação ande não houver conflito , o seu
programa irá custodiar operações na Base De Dados , consumindo Recurso
do Servidor ... Vale a Pena????
É uma questão de Custo Benfecio.. Nesta situação na maior parte das
vezes vence o Custo.
Qauntas vezes durante o Dia terá este conflito e quantas veses não terá
Para verificar isto , mesmo na situação ande não houver conflito , o seu
programa irá custodiar operações na Base De Dados , consumindo Recurso
do Servidor ... Vale a Pena????
GOSTEI 0