Demonstra Passo a passo: Estendendo o Cache do banco de dados Local para sincronização bidirecional de suporte
Você pode adicionar um Cache Local do banco de dados item ao seu projeto para configurar um local SQL Server Compact 3.5 banco de dados em cache e gerar um conjunto de classes parciais permitem que Microsoft Synchronization Services for ADO.NET. Porque Visual Studio gera classes parciais, você pode escrever código para adicionar a funcionalidade de sincronização e ainda manter a capacidade de exibir e alterar as configurações do Configurar sincronização de dados caixa de diálogo. Para obter mais informações sobre classes parciais, consulte Como: Dividir a uma classe em Classes parciais (Designer de classe).
Por padrão, o Configurar sincronização de dados caixa de diálogo permite que você configure Synchronization Services apenas para download. Isso significa que, depois de configurar a sincronização de dados, chamando Synchronize() só baixará as alterações do servidor para o banco de dados do cliente. Uma das maneiras mais comuns para estender o código de sincronização é configurar a sincronização bidirecional. Isso permite carregar alterações do cliente ao servidor. Para habilitar a sincronização bidirecional, recomendamos que você estender o código gerado das seguintes maneiras:
Defina a direção de sincronização como bidirecional.
Adicione código para lidar com conflitos de sincronização.
Remova colunas de controle dos comandos de sincronização do servidor.
Pré-requisitos
Antes de começar este passo a passo, você deve concluir Demonstra Passo a passo: Criando um aplicativo ocasionalmente conectado. Depois de concluir essa explicação passo a passo, você tem um projeto que contém um Cache Local do banco de dados item e um aplicativo Windows Forms que permite baixar alterações da tabela Northwind Customers para um banco de dados compacto do SQL Server. Agora você está pronto para carregar esse passo a passo e adicionar a funcionalidade bidirecional.
Observação |
---|
Seu computador pode mostrar nomes ou locais diferentes para alguns dos elementos da interface do usuário do Visual Studio nas instruções a seguir. A edição do Visual Studio que você possui e as configurações que você usa determinam esses elementos. Para obter mais informações, consulte Configurações do Visual Studio. |
Para abrir a solução OCSWalkthrough
Abra Visual Studio.
Sobre o arquivo abrir uma solução existente ou um projeto de menu e localize a solução OCSWalkthrough. Este é o arquivo OCSWalkthrough.
Definindo a direção da sincronização
O Configurar sincronização de dados caixa de diálogo permite que você defina a SyncDirection() a propriedade para um DownloadOnly() ou Snapshot(). Para habilitar a sincronização bidirecional, defina a SyncDirection() propriedade para Bidirectional() para cada tabela que você deseja habilitar para carregamento de alterações.
Para definir a direção da sincronização
Clique com o botão direito NorthwindCache. Sync e, em seguida, clique em Exibir código. A primeira hora que você fizer isso, o Visual Studio cria um arquivo de NorthwindCache no nó NorthwindCache. Sync Solution Explorer. Este arquivo contém uma classe parcial do NorthwindCacheSyncAgent e você pode adicionar outras classes, conforme necessário.
No arquivo de classe NorthwindCache, adicione código para que o NorthwindCacheSyncAgent.OnInitialized() método parece com o seguinte código:
partial void OnInitialized() { this.Customers.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional; }
Private Sub OnInitialized() Me.Customers.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional End Sub
Abra o Form1 no Editor de Códigos.
No arquivo Form1, modifique a linha do código de SynchronizeButton_Click manipulador de eventos para que ele inclua upload e estatísticas de download:
MessageBox.Show("Changes downloaded: " + syncStats.TotalChangesDownloaded.ToString() + Environment.NewLine + "Changes uploaded: " + syncStats.TotalChangesUploaded.ToString());
MessageBox.Show("Changes downloaded: " & _ syncStats.TotalChangesDownloaded.ToString & _ Environment.NewLine & _ "Changes uploaded: " & _ syncStats.TotalChangesUploaded.ToString)
Testando o aplicativo
Agora o aplicativo está configurado para executar ambos os carregamentos e downloads durante a sincronização.
Para testar o aplicativo
Pressione F5.
No formulário, atualizar um registro e clique no Salvar o botão (o ícone do disco, na barra de ferramentas).
Clique em Sincronizar agora.
Aparece uma caixa de mensagem que contém informações sobre os registros sincronizados. As estatísticas mostram que uma linha foi carregada e outra foi baixada, embora nenhuma alteração foi feita no servidor. O download adicional ocorre porque alterações do cliente são repetidas cliente depois de aplicadas no servidor. Para obter mais informações, consulte "Determinando qual cliente fez uma alteração de dados" em como: Usar um sistema de controle de alterações personalizado.
Clique em OK para fechar a caixa de mensagem, mas deixe o aplicativo em execução.
Agora você irá alterar o mesmo registro no cliente e servidor para forçar um conflito (uma violação de simultaneidade) durante a sincronização.
Para testar o aplicativo e forçar a um conflito.
No formulário, atualizar um registro e clique no Salvar botão.
Com o aplicativo ainda em execução, use Server Explorer/Database Explorer (ou outra ferramenta de gerenciamento de banco de dados) para se conectar ao banco de dados do servidor.
Para demonstrar o comportamento padrão para resolução de conflitos em Server Explorer/Database Explorer, atualize o mesmo registro que você atualizou no formulário, mas alterá-lo para um valor diferente e confirme a alteração. (Mover para fora da linha modificada).
Volte para o formulário e, em seguida, clique em Sincronizar agora.
Verifique se a atualização do banco de dados de grade e o servidor de aplicativo. Observe que a atualização que é feita no servidor substituiu a atualização no cliente. Para obter informações sobre como alterar esse comportamento de resolução de conflitos, consulte a próxima seção deste tópico, "Adicionando código para lidar com conflitos de sincronização".
Adicionando código para lidar com conflitos de sincronização
Em Synchronization Services, uma linha está em conflito se ela tiver sido alterada no cliente e no servidor entre as sincronizações. Synchronization ServicesFornece um conjunto de recursos que podem ser usados para detectar e resolver conflitos. Nesta seção, você adicionará resolução básica de conflitos em que a mesma linha é atualizada no cliente e servidor. Outros tipos de conflitos incluem uma linha excluída em um banco de dados e atualizada em outro ou linhas que possuem a chaves primárias duplicadas inseridas nos dois bancos de dados. Para obter mais informações sobre como detectar e resolver conflitos, consulte como: Manipular dados conflitos e erros.
Observação |
---|
O exemplo de código fornece um exemplo básico de resolução de conflitos. A maneira na qual você resolve conflitos depende dos requisitos do seu aplicativo e a lógica de negócios. |
Adicione código para manipular o servidor ApplyChangeFailed o cliente e o evento ApplyChangeFailed de evento. Esses eventos são gerados quando uma linha não pode ser aplicada devido um conflito ou erro. Os métodos que manipulam esses eventos verificam o tipo de conflito e especificar que a atualização cliente / conflitos de atualização de servidor devem ser resolvidos forçando a alteração do cliente a serem gravados no banco de dados do servidor. O comando de sincronização que aplica atualizações no banco de dados do servidor inclui lógica para reconhecer quando uma alteração deve ser forçada. Este comando está incluído no código na próxima seção deste tópico, "Remoção Server colunas de controle dos comandos de sincronização".
As etapas executadas para adicionar conflitos diferem, dependendo se você estiver usando o C# ou Visual Basic.
Para adicionar conflitos
Se você estiver usando o C#, adicione o código NorthwindCache. cs e Form1. cs. No NorthwindCache. cs, adicione o seguinte código após o término da classe NorthwindCacheSyncAgent:
public partial class NorthwindCacheServerSyncProvider { partial void OnInitialized() { this.ApplyChangeFailed += new System.EventHandler<Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs> (NorthwindCacheServerSyncProvider_ApplyChangeFailed); } private void NorthwindCacheServerSyncProvider_ApplyChangeFailed(object sender, Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e) { if (e.Conflict.ConflictType == Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate) { // Resolve a client update / server update conflict by force writing // the client change to the server database. System.Windows.Forms.MessageBox.Show("A client update / server update conflict " + "was detected at the server."); e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite; } } } public partial class NorthwindCacheClientSyncProvider { public void AddHandlers() { this.ApplyChangeFailed += new System.EventHandler<Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs> (NorthwindCacheClientSyncProvider_ApplyChangeFailed); } private void NorthwindCacheClientSyncProvider_ApplyChangeFailed(object sender, Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e) { if (e.Conflict.ConflictType == Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate) { // Resolve a client update / server update conflict by keeping the // client change. e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue; } } }
No Form1. cs, modifique o código de SynchronizeButton_Click manipulador de eventos, de modo que ele chama o AddHandler método adicionado na etapa anterior para NorthwindCache. cs:
NorthwindCacheSyncAgent syncAgent = new NorthwindCacheSyncAgent(); NorthwindCacheClientSyncProvider clientSyncProvider = (NorthwindCacheClientSyncProvider)syncAgent.LocalProvider; clientSyncProvider.AddHandlers(); Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();
Se você estiver usando Visual Basic, no NorthwindCache. vb, adicione o seguinte código após a End Class a instrução para o NorthwindCacheSyncAgent classe.
Partial Public Class NorthwindCacheServerSyncProvider Private Sub NorthwindCacheServerSyncProvider_ApplyChangeFailed( _ ByVal sender As Object, ByVal e As _ Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs) _ Handles Me.ApplyChangeFailed If e.Conflict.ConflictType = _ Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate Then ' Resolve a client update / server update conflict by force writing ' the client change to the server database. MessageBox.Show("A client update / server update" & _ " conflict was detected at the server.") e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite End If End Sub End Class Partial Public Class NorthwindCacheClientSyncProvider Private Sub NorthwindCacheClientSyncProvider_ApplyChangeFailed( _ ByVal sender As Object, ByVal e As _ Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs) _ Handles Me.ApplyChangeFailed If e.Conflict.ConflictType = _ Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate Then ' Resolve a client update / server update conflict by keeping the ' client change. e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue End If End Sub End Class
Para sincronizar e exibir a resolução de conflitos
Pressione F5.
No formulário, atualizar um registro e clique no Salvar botão.
Em Server Explorer/Database Explorer, atualize o mesmo registro que você atualizou no formulário, mas alterá-lo para um valor diferente e, em seguida, confirmar a alteração.
Volte para o formulário e, em seguida, clique em Sincronizar agora.
Verifique se a atualização do banco de dados de grade e o servidor de aplicativo. Observe que a atualização que você fez no cliente substituiu a atualização no servidor.
Removendo colunas de controle dos comandos de sincronização do servidor
Quando o Cache Local do banco de dados é criado, as colunas que são usadas para controlar as alterações no banco de dados do servidor são baixadas para o cliente. (Esta explicação passo a passo, as colunas são CreationDate e LastEditDate). Para oferecer suporte à sincronização bidirecional e ajudam a garantir a convergência dos dados no cliente e servidor, remova essas colunas dos comandos SQL que aplicam alterações no banco de dados do servidor. Você também pode remover as colunas dos comandos que selecionam alterações do servidor a serem aplicadas ao cliente, mas isso não é necessário. Devido a restrições em algumas alterações de esquema do banco de dados do cliente, de colunas não podem ser descartadas. Para obter mais informações sobre os comandos de sincronização, consulte como: Especifique o Snapshot, Download, Upload e sincronização bidirecional.
Observação |
---|
Se você usar SQL Server 2008 controle de alterações, colunas de controle não são adicionadas para tabelas. Nesse caso, você não precisará alterar os comandos que aplicam alterações ao servidor. |
O código a seguir redefinições de dois comandos são definidos como propriedades na SyncAdapter o objeto para a tabela Customers: o InsertCommand() e UpdateCommand() Propriedades. Os comandos que foram gerados pela Configurar sincronização de dados referências de contidos de caixa de diálogo às colunas CreationDate e LastEditDate. No código a seguir, esses comandos são redefinidos na OnInitialized método de CustomersSyncAdapter classe. O DeleteCommand() propriedade não foi redefinida porque ele não afeta a coluna CreationDate ou LastEditDate.
As variáveis de cada comando SQL são usadas para passar dados e metadados entre Synchronization Services, o cliente e servidor. As seguintes variáveis de sessão são usadas nos comandos abaixo:
@sync\_row\_count: Retorna o número de linhas afetadas pela última operação no servidor. Em SQL Server bancos de dados, @@rowcount fornece o valor para esta variável.
@sync\_force\_write: Usado para forçar a aplicação de uma alteração que falhou devido um conflito ou erro.
@sync\_last\_received\_anchor: Usado para definir o conjunto de alterações a serem sincronizados durante uma sessão.
Para obter mais informações sobre variáveis de sessão, consulte como: Usar variáveis de sessão.
Para remover colunas de controle dos comandos de sincronização
Adicione o seguinte código para o NorthwindCache classe (NorthwindCache. vb ou NorthwindCache. cs) após a End Class a instrução para o NorthwindCacheServerSyncProvider classe.
public partial class CustomersSyncAdapter { partial void OnInitialized() { // Redefine the insert command so that it does not insert values // into the CreationDate and LastEditDate columns. System.Data.SqlClient.SqlCommand insertCommand = new System.Data.SqlClient.SqlCommand(); insertCommand.CommandText = "INSERT INTO dbo.Customers ([CustomerID], [CompanyName], " + "[ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], " + "[Country], [Phone], [Fax] )" + "VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, " + "@Region, @PostalCode, @Country, @Phone, @Fax) SET @sync_row_count = @@rowcount"; insertCommand.CommandType = System.Data.CommandType.Text; insertCommand.Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar); insertCommand.Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@Address", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@City", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@Region", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@Country", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar); insertCommand.Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int); insertCommand.Parameters["@sync_row_count"].Direction = System.Data.ParameterDirection.Output; this.InsertCommand = insertCommand; // Redefine the update command so that it does not update values // in the CreationDate and LastEditDate columns. System.Data.SqlClient.SqlCommand updateCommand = new System.Data.SqlClient.SqlCommand(); updateCommand.CommandText = "UPDATE dbo.Customers SET [CompanyName] = @CompanyName, [ContactName] " + "= @ContactName, [ContactTitle] = @ContactTitle, [Address] = @Address, [City] " + "= @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] = @Country, " + "[Phone] = @Phone, [Fax] = @Fax " + "WHERE ([CustomerID] = @CustomerID) AND (@sync_force_write = 1 " + "OR ([LastEditDate] <= @sync_last_received_anchor)) SET @sync_row_count = @@rowcount"; updateCommand.CommandType = System.Data.CommandType.Text; updateCommand.Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@Address", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@City", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@Region", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@Country", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar); updateCommand.Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar); updateCommand.Parameters.Add("@sync_force_write", System.Data.SqlDbType.Bit); updateCommand.Parameters.Add("@sync_last_received_anchor", System.Data.SqlDbType.DateTime); updateCommand.Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int); updateCommand.Parameters["@sync_row_count"].Direction = System.Data.ParameterDirection.Output; this.UpdateCommand = updateCommand; } }
Partial Public Class CustomersSyncAdapter Private Sub OnInitialized() ' Redefine the insert command so that it does not insert values ' into the CreationDate and LastEditDate columns. Dim insertCommand As New System.Data.SqlClient.SqlCommand With insertCommand .CommandText = "INSERT INTO dbo.Customers ([CustomerID], [CompanyName], " & _ "[ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], " & _ "[Country], [Phone], [Fax] )" & _ "VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, " & _ "@Region, @PostalCode, @Country, @Phone, @Fax) SET @sync_row_count = @@rowcount" .CommandType = System.Data.CommandType.Text .Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar) .Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar) .Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar) .Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Address", System.Data.SqlDbType.NVarChar) .Parameters.Add("@City", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Region", System.Data.SqlDbType.NVarChar) .Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Country", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar) .Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int) .Parameters("@sync_row_count").Direction = ParameterDirection.Output End With Me.InsertCommand = insertCommand ' Redefine the update command so that it does not update values ' in the CreationDate and LastEditDate columns. Dim updateCommand As New System.Data.SqlClient.SqlCommand With updateCommand .CommandText = "UPDATE dbo.Customers SET [CompanyName] = @CompanyName, [ContactName] " & _ "= @ContactName, [ContactTitle] = @ContactTitle, [Address] = @Address, [City] " & _ "= @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] = @Country, " & _ "[Phone] = @Phone, [Fax] = @Fax " & _ "WHERE ([CustomerID] = @CustomerID) AND (@sync_force_write = 1 " & _ "OR ([LastEditDate] <= @sync_last_received_anchor)) SET @sync_row_count = @@rowcount" .CommandType = System.Data.CommandType.Text .Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar) .Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar) .Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Address", System.Data.SqlDbType.NVarChar) .Parameters.Add("@City", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Region", System.Data.SqlDbType.NVarChar) .Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Country", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar) .Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar) .Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar) .Parameters.Add("@sync_force_write", System.Data.SqlDbType.Bit) .Parameters.Add("@sync_last_received_anchor", System.Data.SqlDbType.DateTime) .Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int) .Parameters("@sync_row_count").Direction = ParameterDirection.Output End With Me.UpdateCommand = updateCommand End Sub End Class
Testando o aplicativo
Para sincronizar e exibir um controle de coluna atualizar
Pressione F5.
No formulário, atualizar um registro alterando um valor na coluna LastEditDate e clique no Salvar botão.
Volte para o formulário e clique em Synchronize Now.
Verifique se a atualização do banco de dados de grade e o servidor de aplicativo. Observe que o valor da coluna do servidor substituiu a atualização no cliente. O processo de atualização é o seguinte:
Synchronization Servicesdetermina que uma linha foi alterada no cliente.
Durante a sincronização, a linha é carregada e aplicada à tabela do banco de dados do servidor. No entanto, as colunas de controle não são incluídas na instrução update. Synchronization Servicesefetivamente executa uma "atualização fictícia" a tabela.
Agora, a linha é ecoada volta ao cliente, mas os comandos que selecionam alterações do servidor incluem as colunas de controle. Portanto, a alteração foi feita no cliente é substituída pelo valor do servidor.
Próximas etapas
Esta explicação passo a passo, você configurou a sincronização bidirecional com básica de conflitos e resolveu o problema potencial de ter colunas do banco de dados do cliente de controle de servidor. Usando classes parciais, você pode estender o Cache Local do banco de dados código de outras maneiras pertinentes. Por exemplo, você pode redefinir os comandos SQL que selecionam alterações do banco de dados do servidor para que os dados sejam filtrados quando ele é baixado para o cliente. Recomendamos que você leia os tópicos de instruções desta documentação para entender as maneiras em que você pode adicionar ou alterar o código de sincronização para atender às necessidades de seus aplicativos. Para obter mais informações, consulte como programa Common Client and Server Synchronization Tasks.
Consulte também
Conceitos
Visão geral sobre aplicativos ocasionalmente conectados
Outros recursos
Como o programa Common Client and Server Synchronization Tasks
ferramentas para ajudá-lo a desenvolver aplicativos (Synchronization Services)