ID do artigo: 320301 - Última revisão: domingo, 1 de fevereiro de 2004 - Revisão: 3.4

COMO: Atualizar dados pai-filho com uma coluna de identidade de um aplicativo do Windows Forms usando uma Web Service in Visual translation from VPE for Csharp .NET

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sumário

Este artigo passo a passo descreve como recuperar um objeto DataSet de um serviço da Web, como enviar DiffGram atualizações para o serviço da Web e, em seguida, como mesclar DiffGram atualizado o cliente DataSet de volta. Esse processo envolve as seguintes etapas:
  1. O aplicativo cliente recupera um objeto de DataSet com dois objetos DataTable em uma relação pai-filho do serviço da Web. A DataTable pai possui uma coluna de identidade/AutoNumeração como chave primária.
  2. O aplicativo cliente, o usuário pode adicionar, excluir e modificar registros pai e filho registros. Novos registros pai recebem um temporário valor de chave primário que é gerado localmente.
  3. O aplicativo cliente envia as alterações de volta para a Web service como um DiffGram.
  4. O serviço da Web atualiza o banco de dados, recupera os valores de chaves primária reais para novos registros pai e, em seguida, propaga os valores da chave que são alterados para os registros filho.
  5. O aplicativo cliente recebe os valores atualizados de serviço da Web e mescla os valores atualizados local DataSet de volta.
Para obter informações adicionais sobre como atualizar uma única tabela usando um serviço da Web, clique no número abaixo para ler o artigo na Base de dados de Conhecimento da Microsoft:
310143  (http://support.microsoft.com/kb/310143/EN-US/ ) COMO: Atualizar dados do servidor por meio de uma Web Service usando o ADO.NET e Visual translation from VPE for Csharp .NET

Requisitos

A lista a seguir descreve o hardware recomendado, software, infra-estrutura de rede e service packs são necessários:
  • Microsoft Windows 2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server ou Windows NT 4.0 Server
  • Microsoft Visual Studio .NET
Este artigo pressupõe que você esteja familiarizado com os seguintes tópicos:
  • O Visual Studio .NET
  • Conceitos básicos do ADO.NET e sintaxe
  • Conceitos básicos do ASP.NET e sintaxe
Os exemplos de código neste artigo use http://localhost como o servidor Web. Além disso, as amostras de código usam o banco de dados Northwind como o banco de dados. O banco de dados Northwind está incluído no Microsoft SQL Server.

Criar o serviço da Web

  1. Para criar um novo projeto do Visual translation from VPE for Csharp ASP.NET Web Service, execute essas etapas:
    1. Inicie o Visual Studio NET..
    2. No menu arquivo , aponte para novo e, em seguida, clique em Project .
    3. Clique em projetos do Visual translation from VPE for Csharp em Tipos de projeto e, em seguida, clique em ASP.NET Web Service em modelos .
    4. Na caixa local , o local padrão é exibido como http://localhost/WebService1. Digite a URL para o servidor (por exemplo, http://localhost executa serviço da Web no seu servidor Web local). Substituir WebService1 com CSharpUpdateData . A URL na caixa local deve aparecer da seguinte maneira:
      http://localhost/CSharpUpdateData
    5. Para fechar a caixa de diálogo New Project , clique em OK .
  2. Em Service1.asmx.cs[Design] página, alterne para modo de exibição código. Observe que a janela de código para o serviço da Web é exibida.
  3. Na parte superior da janela código, adicione a instrução a seguir usando :
    using System.Data.SqlClient;
  4. Adicione o seguinte para a implementação da classe Service1:
            [WebMethod]
            public DataSet GetData()
            {
                SqlConnection conn = new SqlConnection ("server=vcdb02;uid=sa;pwd=ricka;database=northwind");
                //Pull back the recent orders for the parent rows.
                SqlDataAdapter daOrder = new SqlDataAdapter("SELECT * FROM Orders WHERE OrderDate >= '05/01/1998'",conn);
                //Get only the appropriate child rows for the parent rows.
                SqlDataAdapter daDetails = new SqlDataAdapter("SELECT * FROM [Order Details] WHERE OrderID in ( SELECT OrderID FROM Orders WHERE OrderDate >= '05/01/1998')",conn);
    
                DataSet ds = new DataSet();
                try
                {
    				
                    //Fill DataSet, and then set DataRelation to move through the DataGrid.
                    conn.Open();
    
                    daOrder.FillSchema(ds,SchemaType.Mapped,"Orders");
                    daOrder.Fill(ds,"Orders");
    
                    daDetails.FillSchema(ds,SchemaType.Mapped,"Details");
                    daDetails.Fill(ds,"Details");
    
                    ds.Relations.Add("OrdDetail", ds.Tables["Orders"].Columns["OrderID"], ds.Tables["Details"].Columns["OrderID"]);
    			
                    DataColumn dc = ds.Tables["Orders"].Columns["OrderID"];
                    dc.AutoIncrement = true;
                    dc.AutoIncrementSeed = -1;
                    dc.AutoIncrementStep = -1;
                }
                catch(SqlException ex)
                {
                    Console.Write (ex.Message.ToString ());
                    Console.Write(ex.InnerException.ToString ());
    
                }
    
                return ds;
            }
    		
            [WebMethod]
            public DataSet UpdateData(DataSet ds)
            {
                SqlConnection conn = new SqlConnection ("server=vcdb02;uid=sa;pwd=ricka;database=northwind");
                //Pull back the recent orders for the parent rows.
                SqlDataAdapter daOrders = new SqlDataAdapter("SELECT * FROM Orders WHERE OrderDate >= '05/01/1998'",conn);
                //Get only the appropriate child rows for the parent rows.
                SqlDataAdapter daDetails = new SqlDataAdapter("SELECT * FROM [Order Details] WHERE OrderID in ( SELECT OrderID FROM Orders WHERE OrderDate >= '05/01/1998')",conn);
    
    			
                try
                {
                    conn.Open();
                    // Get commands for the Orders table.
                    // Reselect record after insert to get new Identity value.
                    // You must get the schema, which you did in GetData(), before you get commands; 
                    // otherwise, the Command builder tries to insert new rows, based 
                    // on the Identity column.
                    SqlCommandBuilder cb = new SqlCommandBuilder(daOrders);
                    daOrders.DeleteCommand = cb.GetDeleteCommand();
                    daOrders.UpdateCommand = cb.GetUpdateCommand();
                    daOrders.InsertCommand = cb.GetInsertCommand();
                    daOrders.InsertCommand.CommandText = String.Concat(daOrders.InsertCommand.CommandText, "; Select * From Orders Where OrderID = @@IDENTITY");
    
                    //UpdateRowSource tells the DataAdapter that there will be a re-selected record.
          
                    daOrders.InsertCommand.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord;
                    //cb = null;
            
    
                    // Get commands for the Order Details table.
                    // Must set the QuotePrefix and QuoteSuffix; 
                    // otherwise, the CommandBuilder does not put brackets ([])
                    // around the table name.
    
                    SqlCommandBuilder cb1 = new SqlCommandBuilder(daDetails);
                    cb1.QuotePrefix = "[";
                    cb1.QuoteSuffix = "]";
                    daDetails.DeleteCommand = cb1.GetDeleteCommand();
                    daDetails.InsertCommand = cb1.GetInsertCommand();
                    daDetails.UpdateCommand = cb1.GetUpdateCommand();
    
    
                    // Create a new DataAdapter based on the original one to prevent the
                    // CommandBuilder from modifying the SQL statements, 
                    // specifically the custom InsertCommand.
                    // You do not need this if you roll your own commands and parameters 
                    // or if you use the Visual Tools to do it.
               
                    SqlDataAdapter daOrd2 = new SqlDataAdapter();
                    daOrd2.DeleteCommand = daOrders.DeleteCommand;
                    daOrd2.InsertCommand = daOrders.InsertCommand;
                    daOrd2.UpdateCommand = daOrders.UpdateCommand;
    
                    // Use a delegate to prevent AcceptChanges from occurring on Deletes and Inserts.
                    // This is for a limitation of the DataAdapter; see Q313540. 
    
                    daOrd2.RowUpdated += new SqlRowUpdatedEventHandler(OnOrd1RowUpdated);
                    daDetails.RowUpdated += new SqlRowUpdatedEventHandler(OnDetailsRowUpdated);
    
    
                    daDetails.Update(GetDeletedRows(ds.Tables["Details"]));
                    daOrd2.Update(GetDeletedRows(ds.Tables["Orders"]));
                    DataRow [] dsArray = ds.Tables["Orders"].Select("", "", DataViewRowState.ModifiedCurrent);
                    daOrd2.Update(ds.Tables["Orders"].Select("", "", DataViewRowState.ModifiedCurrent));
                    daDetails.Update(ds.Tables["Details"].Select("", "", DataViewRowState.ModifiedCurrent));
    
                    daOrd2.Update(ds.Tables["Orders"].Select("", "", DataViewRowState.Added));
    
                    ds.EnforceConstraints = false;
                    daDetails.Update(ds.Tables["Details"].Select("","", DataViewRowState.Added));
                    ds.EnforceConstraints = true;
    
                    conn.Close();
    
    				
    
                }
                catch(SqlException ex)
                {
                    Console.Write (ex.Message.ToString ());
                    Console.Write(ex.InnerException.ToString ());
                }
                return ds;
            }
    
    
            protected static void OnOrd1RowUpdated(object sender, SqlRowUpdatedEventArgs args)
            {
                if(args.StatementType == StatementType.Insert || args.StatementType == StatementType.Delete )
                    args.Status = UpdateStatus.SkipCurrentRow;
    
            }
            protected static void OnDetailsRowUpdated(object sender, SqlRowUpdatedEventArgs args)
            {
                if(args.StatementType == StatementType.Insert )
                {
                    // Do not allow the AcceptChanges to occur on this row.
                    args.Status = UpdateStatus.SkipCurrentRow;
    
                    // Get the current, actual primary key value so that you can plug it back
                    // in after you get the correct original value that was generated for the child row.
                    int currentkey = (int)args.Row["OrderID"];
                    // This is where you get a correct original value key that is stored to the child row. 
                    // You pull the original, pseudo key value from the parent, plug it in as the child row's primary key
                    // field, and then accept changes on it. Specifically, this is why you turned off EnforceConstraints.
                    args.Row["OrderID"] = args.Row.GetParentRow("OrdDetail")["OrderID",DataRowVersion.Original];
                    args.Row.AcceptChanges();
                    // Store the actual primary key value in the foreign key column of the child row.
                    args.Row["OrderID"] = currentkey;
                }
    
                if(args.StatementType == StatementType.Delete )
                    args.Status = UpdateStatus.SkipCurrentRow;
    
            }
            private DataRow [] GetDeletedRows(DataTable dt)
            {
                DataRow [] dr ;
                if(dt == null)
                    return null;
                dr = dt.Select("","",DataViewRowState.Deleted );
                if(dr.Length ==0 || dr[0] != null)
                    return dr;
                // Workaround:
                // With a remoted DataSet, Select returns the array elements
                // that are filled with Nothing/null instead of DataRow objects.
    					
                for(int i=0; i < (int)dt.Rows.Count; i++)
                {
                    if(dt.Rows[i].RowState ==DataRowState.Deleted )
                        dr[i]=dt.Rows[i];
                }
                return dr;
    						
    
            } 
    					
  5. Modificar as seqüências SqlConnection se conectar ao servidor que está executando o SQL Server.

Testar o serviço da Web

  1. Pressione F5 para compilar e executar o serviço da Web. Observe que uma página da Web é retornada com a URL http://localhost/CSharpUpdateData/Service1.asmx. Nesta página da Web, você pode interagir com o serviço da Web do Microsoft Internet Explorer.
  2. Na página da Web Service1.asmx, clique em GetData . Observe que uma página da Web é retornada que exibe detalhes sobre o método GetData da Web.
  3. Feche as páginas da Web.

Criar o aplicativo cliente

  1. Para criar um novo projeto do Visual translation from VPE for Csharp Windows Application, execute essas etapas:
    1. No menu arquivo no Visual Studio. NET, aponte para novo e, em seguida, clique em Project .
    2. Na caixa de diálogo New Project , clique em projetos do Visual translation from VPE for Csharp em Project Types e clique em Windows Application em modelos . Por padrão, o Form1 é adicionado para o projeto.
  2. Arraste um controle Button e um controle DataGrid da caixa de ferramentas para Form1. Por padrão, os controles são chamados button1 e dataGrid1 respectivamente.
  3. Altere a propriedade Name do button1 para btnSave e, em seguida, altere a propriedade texto de button1 para Salvar .
  4. No menu Project , clique em Add Web Reference . Digite a URL para seu Web service (no caso, tipo http://localhost/CSharpUpdateData/Service1.asmx ), pressione ENTER e, em seguida, clique em Add Reference . Observe que a entrada para essa referência da Web aparece no Solution Explorer.
  5. Adicione o seguinte código à classe Form1 para declarar um membro de nível de formulário para o DataSet :
           private System.Data.DataSet ds;
    					
  6. Clique duas vezes o formulário para alternar para modo de exibição código e observar que o Visual Studio .NET gera o método Form1_Load . Adicione o seguinte código para o método Form1_Load :
        localhost.Service1 sv = new localhost.Service1();
        ds = sv.GetData ();
           
        dataGrid1.DataSource = ds;
        dataGrid1.DataMember = "Orders";
    					
  7. Alterne para o modo de formulário.
  8. Abra a janela código do botão Salvar e, em seguida, adicione o seguinte código ao manipulador de evento btnSave_Click :
        localhost.Service1 sv = new localhost.Service1();
    
        DataSet MyChangedRows;
    
        dataGrid1.DataMember = "";
        dataGrid1.DataSource = null;
        //Pull out only what you must send over the wire.
        MyChangedRows = ds.GetChanges();
        MyChangedRows = sv.UpdateData(MyChangedRows);
    
        //You must accept changes on the DataSet because of a known problem. See Q313540.
    
        ds.AcceptChanges();
    
        ds.EnforceConstraints = false;
    
        //Merge in the parent rows first and then the child rows.
        ds.Merge(MyChangedRows.Tables["Orders"], false, MissingSchemaAction.Ignore);
        ds.Merge(MyChangedRows.Tables["details"], false, MissingSchemaAction.Ignore);
    
        //Accept changes that you have made to the DataSet.
        ds.AcceptChanges();
        //Turn on the integrity constraints that you turned off earlier.
        ds.EnforceConstraints = true;
    
        dataGrid1.DataSource = ds;
        dataGrid1.DataMember = "Orders";
    					

Teste o aplicativo cliente

  1. Pressione F5 para compilar e executar o aplicativo cliente.
  2. Na dataGrid1 , modifique alguns dos dados e, em seguida, clique em Salvar .

    Observação : não alterar o campo de chave. Se você alterar o campo de chave, você receber uma mensagem de erro, que declara que são significativas integridade referencial no servidor.
  3. Adicione uma linha filho a uma linha pai existente. Observe que a linha filho recebe automaticamente o valor correto da chave estrangeira.
  4. Adicione os seguintes valores para uma nova linha pai e uma nova linha filho e, em seguida, clique em Salvar . Observe os seguintes valores de chave:
    • Orders.CustomerID=RATTC
    • Orders.EmployeeID=1
    • Orders.OrderDate=2/2/2002
    • Details.ProductID=1
    • Details.UnitPrice=18
    • Details.Quantity=1
    • Details.Discount=0

Referências

Para obter informações adicionais, clique nos números abaixo para ler os artigos na Base de dados de Conhecimento da Microsoft:
310143  (http://support.microsoft.com/kb/310143/EN-US/ ) COMO: Atualizar dados do servidor por meio de uma Web Service usando o ADO.NET e Visual translation from VPE for Csharp .NET
313483  (http://support.microsoft.com/kb/313483/EN-US/ ) INFO: Guia para objetos de DataAdapter do ADO.NET

A informação contida neste artigo aplica-se a:
  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft ADO.NET 1.1
  • Microsoft ADO.NET 1.0
  • Microsoft ASP.NET 1.1
  • Microsoft ASP.NET 1.0
Palavras-chave: 
kbmt kbdatabinding kbhowtomaster kbsqlclient kbsystemdata KB320301 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 320301  (http://support.microsoft.com/kb/320301/en-us/ )