Visual Basic, VB .NET, ASP, Active X, Access, SQL Server

Atualizações Em Recordsets do lado Cliente 

Considere a seguinte atualização em um recordset ADO conectado 
 
Dim rs As New Recordset 
rs.CursorLocation = adUseClient 
rs.Open "SELECT * from Clientes", _ 
STRING_DE_CONEXAO, , adLockOptimistic 
rs.Update "Nome", "Carlos Gomes" 
rs.Close 

ADO gera uma Query Based Update (QBU) para realizar esta operação: 
 
UPDATE "Clientes" SET "Nome"= ? 
WHERE "IDCliente" = ? AND "Nome"= ? 

Valores de parâmetros são fornecidos como parte do processo de atualização 
A cláusula WHERE tem duas partes: 

-Os campos de 'novos valores' (mudados) 
-A chave primária 


Campos de Novos Valores

ADO identifica campos de 'Novos Valores' comparando duas propriedades de cada objeto Field: 

-UnderlyingValue 
-Value 

O nome da tabela e da coluna para as cláusulas UPDATE e SET são derivadas das propriedades dinâmicas de um objeto Field: 


-SCHEMANAME, CATALOGNAME 
-BASETABLENAME 
-BASECOLUMNNAME 


Identificação de Linha 

O UPDATE precisa identificar a linha em questão. ADO identifica a chave primária. 

-Usa a propriedade dinâmica KEYCOLUMN 

 Se o recordset não contém uma chave primária ... 

-O UPDATE pode atualizar mais de um registro. ADO gera um erro, mas atualiza mesmo assim.
-Com o SQLServer 7, ADO automaticamente recupera as chaves primárias para os recordsets atualizáveis. Armazenadas como 'Colunas Ocultas' 

Bloqueio 

Por que a cláusula WHERE, abaixo, contém o(s) campo(s) de 'Novo(s) Valor(es)'? 

UPDATE "Clientes" SET "Nome" = ? 
WHERE "IDCliente" = ? AND "Nome" = ? 

Acima, na cláusula WHERE, "IDCliente" = ? identifica a linha, "Nome" = ? simula bloqueio.


Após o UPDATE, ADO checa o número de registros afetados. Um valor de 0 gera um erro: 

-2147217864 Linha não pode ser bloqueada para atualização. 
Alguns valores podem ter sido mudados desde que foi lida pela última vez. 

Bloqueio baseado nos campos de 'Novos Valores' não é o mesmo que bloqueio de registro inteiro. 

ADO permite que você controle que campos são usados para gerar a cláusula WHERE: 

rs.Properties("Update Criteria") = adCriteriaKey 
rs.Properties("Update Criteria") = adCriteriaUpdCols 
rs.Properties("Update Criteria") = adCriteriaAllCols 
rs.Properties("Update Criteria") = adCriteriaTimeStamp
 

Atualizando Joins 

No mundo real, muitas consultas são baseadas em joins, e as pessoas querem atualizá-las.

Considere 

SELECT R.IDRegiao As ID ,R.DescricaoDeRegiao, 
T.IDTerritorio, T.DescricaoDeTerritorio, T.IDRegiao 
FROM Regioes R, Territorios T 
where R.IDRegiao = 4 and R.IDRegiao = T.IDRegiao 



Esta consulta retorna os seguintes dados 

ID Descrição da Região IDTerritorio Descrição do Territorio IdRegiao
4 Sudeste 38222 Santos 1
4 Sudeste 43234 Rio de Janeiro 1
4 Sudeste 12984 São Paulo 1
4 Sudeste 41344 Campos 1
4 Sudeste 25421 Campinas 1
4 Sudeste 13754 Ribeirão Preto 1
4 Sudeste 23456 Goitacazes 1
4 Sudeste 29872 Sorocaba 1

Join - rs.Update

Aqui está o que ocorre quando eu mudo o campo DescricaoDeRegiao da tabela Regioes e chamo um Update: 

UPDATE Regiao" SET "DescricaoDeRegiao"=? 
WHERE "DescricaoDeRegiao"=? AND "IDRegiao"=? 

... e quando eu mudo DescricaoDeTerritorio da tabela Territorios e chamo Update: 

UPDATE "Territorios" SET "DescricaoDeTerritorio"=? 
WHERE "IDTerritorio=? 
AND "DescricaoDeTerritorio"=? 

... e se eu mudo ambos estes campos e chamo Update 

UPDATE "Regioes" SET "DescricaoDeRegiao"=? 
WHERE "DescricaoDeRegiao"=? AND "IDRegiao"=? 

UPDATE "Territorios" SET "DescricaoDeTerritorio"=? 
WHERE "IDTerritorio"=? 
AND "DescricaoDeTerritorio"=? 

Join - rs.Delete 

A diversão começa quando eu chamo rs.Delete: 

DELETE FROM "Territorios" WHERE "IDTerritorio"=? 
DELETE FROM "Regioes" WHERE "IDRegiao"=? 

Eu provavelmente não quero que isto aconteça! 

Se o meu banco de dados tem integridade referencial, isto irá causar um erro. 


Join - rs.AddNew 

Se eu apenas forneço os campos da tabela Territorios 

INSERT INTO Territorios" ("IDTerritorio","DescricaoDeTerritorio","IDRegiao") VALUES (?,?,?) 

Isto parece estar bem, mas: 

- Agora há vazios no recordset, porque eu não forneci valores para os campos de Regioes 
-Se eu fornecer valores para estes campos, ADO gera um comando INSERT para a tabela Regioes. O quê provavelmente eu não quero também! 

O Problema 

QBU tem dois problemas potenciais quando o recordset é baseado em joins: 

1.rs.Delete tentará deletar um registro de cada tabela usada no recordset 

2.Para evitar a geração de um indesejável insert após um rs.AddNew, eu tenho vazios no meu recordset onde os dados deveriam estar. 

A Soluçao 

ADO 2.1 indroduziu o conceito de 'Unique Table' (Tabela Única): 

-Comandos Delete são gerados apenas para 'Unique Tables' 
-Quando uma 'Unique Table' é especificada, um comando Resync personalizado pode ser usado para preencher os vazios deixados após uma chamada a rs.AddNew 


Especificando uma tabela única 

rs.Properties("Unique Catalog") = "NorthWind" 
rs.Properties("Unique Table") = "Territorios" 
rs.Delete 

gera o seguinte SQL: 

DELETE FROM "Territorios" WHERE "IDTerritorio"=? 
Especificando um Resync personalizado 

rs.Properties("Unique Catalog") = "NorthWind" 
rs.Properties("Unique Table") = "Territorios" 
rs.Properties("Resync Command") = _  ' ATRIBUI A PROPRIEDADE  DINÂMICA
                                                                     ' RESYNC COMMAND 

"select R.IDRegiao As ID, " & _ 
"R.DescricaoDeRegiao, T.IDTerritorio, " & _ 
"T.DescricaoDeTerritorio, T.IDRegiao " & _ 
"from Regioes R, Territorios T Where " & _                                           

"T.IDTerritorio = ? And R.IDRegiao = T.IDRegiao"  'INCLUI UM MARCADOR DE
                                                                                          'PARÂMETRO PARA  CADA
                                                                                          'CAMPO DA CHAVE
                                                                                          'PRIMÁRIA DA TABELA ÚNICA

rs.AddNew 
rs!IDTerritorio = 1000 
rs!DescricaoDeTerritorio = "Sorocaba" 
rs!IDRegiao = 4 
rs.Update ' ADICIONA SEM TOCAR NA TABELA REGIOES 
rs.Resync adAffectCurrent 'CHAMA RESYNC PARA PREENCHER OS VAZIOS