Artigo: 320301 - Última revisão: domingo, 1 de Fevereiro de 2004 - Revisão: 3.4

COMO: Actualizar dados de ascendente-subordinado com uma coluna de identidade a partir de uma aplicação de formulários do Windows utilizando um Web Service no Visual C# .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 | Reduzir tudo

Sumário

Este artigo passo a passo descreve como obter um objecto de DataSet a partir de um serviço Web, como enviar DiffGram actualizações para o serviço da Web e, em seguida, como intercalar DiffGram actualizado novamente o cliente DataSet . Este processo envolve os seguintes passos:
  1. A aplicação cliente obtém um objecto de DataSet com dois objectos de DataTable numa relação principal-subordinado do serviço Web. O DataTable principal tem uma coluna de identidade/numeração automática como chave primária.
  2. Na aplicação cliente, o utilizador pode adicionar, eliminar e modificar registos principal e subordinado registos. Novos registos principal recebem um temporário valor chave primária que é gerado localmente.
  3. A aplicação cliente envia alterações para a Web serviço como um DiffGram.
  4. O serviço Web actualiza a base de dados, obtém reais valores de chave primária para novos registos principal e, em seguida, propaga valores da chave são alterados para registos subordinados.
  5. A aplicação cliente recebe os valores actualizados do serviço Web e, em seguida, intercala os valores actualizados para o local DataSet .
Para obter informações adicionais sobre como actualizar uma única tabela utilizando um serviço Web, clique no número de artigo existente abaixo para visualizar o artigo na base de dados de conhecimento da Microsoft:
310143  (http://support.microsoft.com/kb/310143/EN-US/ ) COMO: O serviço de actualização de dados do servidor através de uma Web utilizando o ADO.NET e Visual C# .NET

Requisitos

A lista seguinte 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 está familiarizado com os seguintes tópicos:
  • Visual Studio .NET
  • Noções básicas do ADO.NET e sintaxe
  • Noções básicas ASP.NET e sintaxe
Os exemplos de código neste artigo utilizam http://localhost como o servidor Web. Além disso, os exemplos de código utilizam a base de dados Adamastor da base de dados. A base de dados Adamastor, incluída no Microsoft SQL Server.

Criar o serviço Web

  1. Para criar um novo projecto do Visual C# ASP.NET Web Service, siga estes passos:
    1. Inicie o Visual Studio NET..
    2. No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
    3. Clique em Visual C# Projects em Project Types e, em seguida, clique em Serviço Web do ASP.NET em modelos .
    4. Na caixa localização , a localização predefinida é apresentada como http://localhost/WebService1. Escreva o URL do servidor (por exemplo, http://localhost executa serviço da Web no servidor Web local). Substituir WebService1 com CSharpUpdateData . O URL na caixa localização deverá aparecer da seguinte forma:
      http://localhost/CSharpUpdateData
    5. Para fechar a caixa de diálogo Novo projecto , clique em OK .
  2. No Service1.asmx.cs[Design] página, mude para vista de código. Repare que aparece a janela código para o serviço Web.
  3. Na parte superior da janela de código, adicione a seguinte instrução utilizando :
    using System.Data.SqlClient;
  4. Adicione o seguinte para a implementação de 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 cadeias SqlConnection ligar ao servidor que esteja a executar o SQL Server.

Testar o serviço Web

  1. Prima F5 para compilar e executar o serviço Web. Repare que é devolvida uma página Web com o URL http://localhost/CSharpUpdateData/Service1.asmx. Nesta página Web, pode interagir com o serviço Web a partir do Microsoft Internet Explorer.
  2. Na página Web Service1.asmx, clique em GetData . Repare que é devolvida uma página Web que apresenta os detalhes acerca do método GetData Web.
  3. Feche as páginas Web.

Criar a aplicação cliente

  1. Para criar um novo projecto de aplicação do Windows do Visual C#, siga estes passos:
    1. No menu ficheiro do Visual Studio. NET, aponte para Novo e, em seguida, clique em projecto .
    2. Na caixa de diálogo Novo projecto , clique em Visual C# Projects em Project Types e, em seguida, clique em Aplicação do Windows em modelos . Por predefinição, o Form1 é adicionada ao projecto.
  2. Arraste um controlo de botão e o controlo DataGrid da caixa de ferramentas ao Form1. Por predefinição, os controlos são denominados button1 e dataGrid1 respectivamente.
  3. Altere a propriedade Name do button1 para btnSave e, em seguida, altere a propriedade texto de button1 para Guardar .
  4. No menu projecto , clique em ' Adicionar referência Web '. Escreva o URL para o serviço Web (neste caso, tipo http://localhost/CSharpUpdateData/Service1.asmx ), prima ENTER e, em seguida, clique em Add Reference . Repare que a entrada para esta referência Web é apresentada no Solution Explorer.
  5. Adicione o seguinte código à classe Form1 para declarar um membro de nível do formulário para DataSet :
           private System.Data.DataSet ds;
    					
  6. Faça duplo clique no formulário para mudar para vista de código e repare que o Visual Studio .NET cria 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. Mude para vista de formulário.
  8. Abra a janela código para o botão Guardar e, em seguida, adicione o seguinte código ao processador de eventos 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";
    					

Testar a aplicação de cliente

  1. Prima F5 para compilar e executar a aplicação cliente.
  2. Na dataGrid1 , modificar alguns dos dados e, em seguida, clique em Guardar .

    Nota : não altere o campo de chave. Se alterar o campo chave, receberá uma mensagem de erro que indica que está a separar a integridade referencial no servidor.
  3. Adicione uma linha subordinada a uma linha principal existente. Repare que a linha subordinada recebe automaticamente o valor de chave externo correcto.
  4. Adicione os seguintes valores para uma nova linha principal e uma nova linha subordinada e, em seguida, clique em Guardar . Tenha em atenção os seguintes valores chaves:
    • 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 de artigo existentes abaixo para visualizar os artigos na Microsoft Knowledge Base:
310143  (http://support.microsoft.com/kb/310143/EN-US/ ) COMO: O serviço de actualização de dados do servidor através de uma Web utilizando o ADO.NET e Visual C# .NET
313483  (http://support.microsoft.com/kb/313483/EN-US/ ) INFO: Guia para objectos de ' DataAdapter ' 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 revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes 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/ )