none
salvando utilizando dataset não tipados RRS feed

  • Pergunta

  • olá Angus, de volta do mesmo problema, -é o que dá andar envolvido em várias coisas ao mesmo tempo-, devo dizer que a coisa não está fácil.
    Estive a ver os atigos do srº Macoratti e nenhum deles responde na totalidade ao meu problema.
    Em primeiro decidi alimentar a grid em que no select faço um join entre tabelas, isto é o que faço :

    conn.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=BDWSERVIDOR.mdb";

    conn.Open();

    str = "select * from utilizadores, filas where utilizadores.ID_util=Filas.ID_util";

    command = new OleDbCommand(str,conn);

    da = new OleDbDataAdapter(command);         

    ds=new DataSet ();

    da.Fill(ds, "utilizadores");

    dataGridView_centro.DataSource = ds;
    dataGridView_centro.DataMember = "utilizadores";

    de seguida criei o updateCommand
    //##########Update tabela Utilizadores#########################

     command = new OleDbCommand("UPDATE utilizadores SET nome_util = @param_nome_util,"+
     "dominio = @param_dominio, tipo_util = @param_tipo_util, passw = @param_passw WHERE ID_util = @param_ID_util", conn);

     command.Parameters.Add("@param_nome_util", OleDbType.Char, 50, "nome_util");
     command.Parameters.Add("@param_dominio", OleDbType.VarChar, 50, "dominio");
     command.Parameters.Add("@param_tipo_util", OleDbType.VarChar, 100, "tipo_util");
     command.Parameters.Add("@param_passw", OleDbType.VarChar, 50, "passw");

     parm = command.Parameters.Add("@param_ID_util", OleDbType.Char, 5, "utilizadores.ID_util");
     parm.SourceVersion = DataRowVersion.Original;

     da.UpdateCommand = command;
     
    //################ Create the InsertCommand##################.
    command = new OleDbCommand("INSERT INTO utilizadores (passw, nome_util,dominio,tipo_util) "
    + "VALUES (@param_passw,@param_nome_util, @param_dominio, @param_tipo_util)", conn);

    command.Parameters.Add("@param_passw", OleDbType.VarChar, 50, "passw");
    command.Parameters.Add("@param_nome_util", OleDbType.Char, 50, "nome_util");
    command.Parameters.Add("@param_dominio", OleDbType.VarChar, 50, "dominio");
    command.Parameters.Add("@param_tipo_util", OleDbType.VarChar, 100, "tipo_util");               

    da.InsertCommand = command;  

     ao clicar no botao salvar executo o seguinte codigo:
     
    changes = ds.GetChanges();
    if (changes != null)
    {
        this.da.Update(this.ds, "utilizadores");       
    }

    funciona, faz update e insert na tabela utilizadores.mas eu como estou a lisar registos resultantes do join da tabela utilizadores e filas,
    também quero fazer update na tabela filas.ainda criei um updateCommand para fazer update na tabela FILAS, isso depois implica fazer
    this.da.Update(this.ds, "filas") para salvar as alterações, só que a tabela filas nao existe no ds.nao sei porque depois de criar o updateCommand para actualizar as filas
    deixou de actualizar a tabela utilizadores.depois tambem ha a questao de inserir na tabela filas depois de inserir na tabela utilizadores.sera que me ajudar?

    sou o rafael, sou de portugal e sou aluno de informatica
    sexta-feira, 30 de janeiro de 2009 16:16

Respostas

  • Você está confundindo um monte de coisas. O seu comando SELECT está retornando UM resultset que é constituído de dados das tabelas "utilizadores" e "filas" do seu banco de dados, e você está jogando esse único resultset dentro de um objeto DataTable chamado "utilizadores" dentro do seu objeto DataSet. É isso o que está sendo feito no método Fill() do objeto DataAdaper aqui:

    da.Fill(ds, "utilizadores");    
     

     

    Não existe mesmo nenhum objeto DataTable chamado "filas" naquele DataSet.

    Isso que você quer fazer (atualizar duas tabelas diferentes usando os mesmos DataAdapter e DataTable), apesar de possível, é irregular, e você terá que fazer algumas coisas que não produzirão um código muito "bonito", se é que me entende. O que você teria que fazer é criar dois comandos, um para atualizar cada tabela, definir a propriedade AcceptChangesDuringUpdate do DataAdapter para false para que possa ser possível duas chamadas ao método Update() do DataAdaper seguidas sem que sejam alteradas automaticamente no DataSet as propriedades que dizem ao DataAdaper o que deve ser atualizado e finalmente invocar manualmente o método AcceptChanges() do DataSet quando as atualizações terminarem.

    Aqui um exemplo utilizando as tabelas Orders e Order Details do banco de exemplos Northwind (se não tiver o banco instalado e quiser testar o código, obtenha o script de geração no link). Declare no escopo da classe:

    private DataSet ds;        
    private SqlConnection cnn;        
    private SqlDataAdapter da;    
     

     

    Para preencher o DataSet e vinculá-lo a um DataGridView use este código:

    // String de conexão.        
    cnn = new SqlConnection("Data Source=.;Initial Catalog=Northwind;Integrated Security=SSPI;");        
           
    // Faz um Join nos dados das tabelas Orders e Order Details.        
    da = new SqlDataAdapter("SELECT * FROM Orders AS O, [Order Details] AS D WHERE O.OrderID = D.OrderID", cnn);        
           
    ds = new DataSet();        
           
    // Preenche um DataTable chamado "OrdersXOrderDetails"         
    // com os dados da consulta.        
    da.Fill(ds, "OrdersXOrderDetails");        
           
    dataGridView1.DataSource = ds.Tables["OrdersXOrderDetails"];       
     

     

    Depois de modificar no DataGridView os valores dos campos CustomerID da tabela Orders e Quantity da tabela Order Details, faça as atualizações na base de dados assim:

    // Comando para a atualização da tabela Orders.     
    SqlCommand cmdOrders = new SqlCommand("UPDATE Orders SET CustomerID = @CustomerID WHERE OrderID = @OrderID", cnn);     
    cmdOrders.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");     
    cmdOrders.Parameters.Add("@OrderID", SqlDbType.Int, 4, "OrderID");     
        
    // Comando para a atualização da tabela Order Details.     
    SqlCommand cmdDetails = new SqlCommand("UPDATE [Order Details] SET Quantity = @Quantity WHERE OrderID = @OrderID1 AND ProductID = @ProductID", cnn);     
    cmdDetails.Parameters.Add("@Quantity", SqlDbType.SmallInt, 2, "Quantity");     
    cmdDetails.Parameters.Add("@OrderID1", SqlDbType.Int, 4, "OrderID1");     
    cmdDetails.Parameters.Add("@ProductID", SqlDbType.Int, 4, "ProductID");     
        
    // Não queremos que o DataAdapter invoque automaticamente o método     
    // AcceptChanges() do DataSet. Queremos fazê-lo manualmnete.     
    da.AcceptChangesDuringUpdate = false;     
        
    // Definimos o comando de atualização da tabela Orders     
    // como o comando utilizado pelo DataAdapter para atualizações.     
    da.UpdateCommand = cmdDetails;     
    da.Update(ds, "OrdersXOrderDetails");     
    da.UpdateCommand = cmdOrders;     
    // Fazemos a atualização.     
    da.Update(ds, "OrdersXOrderDetails");     
        
        
    // Definimos o comando de atualização da tabela Order Details     
    // como o comando utilizado pelo DataAdapter para atualizações.     
    da.UpdateCommand = cmdDetails;     
    // Fazemos a atualização.     
    da.Update(ds, "OrdersXOrderDetails");     
        
    // Aceitamos as alterações feitas no DataSet depois das atualizações.     
    ds.AcceptChanges();    
     

     

    Alternativamente você poderia criar um único objeto Command contendo ambos os comandos de atualização a serem executados, isso possibilitaria permitir ao DataAdapter continuar a invocar o método AcceptChanges() do DataSet automaticamente. Nesse caso o último trecho de código poderia ser alterado para isto:

    // Criamos um objeto comando contendo os comando de atualização das tabelas Orders e Order Details.         
    SqlCommand cmd = new SqlCommand("UPDATE Orders SET CustomerID = @CustomerID WHERE OrderID = @OrderID; UPDATE [Order Details] SET Quantity = @Quantity WHERE OrderID = @OrderID1 AND ProductID = @ProductID", cnn);        
    cmd.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");        
    cmd.Parameters.Add("@OrderID", SqlDbType.Int, 4, "OrderID");        
    cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt, 2, "Quantity");        
    cmd.Parameters.Add("@OrderID1", SqlDbType.Int, 4, "OrderID1");        
    cmd.Parameters.Add("@ProductID", SqlDbType.Int, 4, "ProductID");        
           
    // Executamos os comandos.        
    da.UpdateCommand = cmd;        
    da.Update(ds, "OrdersXOrderDetails");     
     

     

    Note que quando duas tabelas são jogadas num mesmo DataTable quaisquer nomes de campos idênticos, como OrderID no exemplo, serão diferenciados: observe que o campo OrderID da tabela Order Details foi modificado para OrderID1 para que seja diferente do campo OrderID da tabela Orders... Como eu disse, isso o que você quer fazer não constitui uma abordagem limpa e eu não a utilizaria. Provavelmente haverá bugs.

    O mínimo que você deveria fazer para um código decente, se quiser utilizar DataAdapters etc., seria a criação de um DataAdapter para interação com a tabela "utilizadores" e outro DataAdaper para interação com a tabela "filas". Preencha um DataTable para cada uma das tabelas com seus respectivos DataAdapters (os DataTables poderiam, claro, estar num mesmo DataSet), fazendo também a atualização das tabelas com seus respectivos DataAdapters. Para exibição e edição dos dados, use a abordagem de relacionamento Mestre/Detalhes com a utilização de dois DataGridViews, um para cada DataTable etc.

    Você encontrará exemplos de relacionamento Mestre/Detalhes nos links abaixo:

    http://www.macoratti.net/08/11/c_db_snc.htm

    http://msdn.microsoft.com/en-us/library/c12c1kx4(vs.80).aspx

     


    "Software Engineers don't have Trophy Wives; they have Presentation Layers."
    • Marcado como Resposta LuisMLPinto sexta-feira, 30 de janeiro de 2009 23:20
    • Editado Angus MacGyver sexta-feira, 30 de janeiro de 2009 23:56
    sexta-feira, 30 de janeiro de 2009 19:24

Todas as Respostas

  • Você está confundindo um monte de coisas. O seu comando SELECT está retornando UM resultset que é constituído de dados das tabelas "utilizadores" e "filas" do seu banco de dados, e você está jogando esse único resultset dentro de um objeto DataTable chamado "utilizadores" dentro do seu objeto DataSet. É isso o que está sendo feito no método Fill() do objeto DataAdaper aqui:

    da.Fill(ds, "utilizadores");    
     

     

    Não existe mesmo nenhum objeto DataTable chamado "filas" naquele DataSet.

    Isso que você quer fazer (atualizar duas tabelas diferentes usando os mesmos DataAdapter e DataTable), apesar de possível, é irregular, e você terá que fazer algumas coisas que não produzirão um código muito "bonito", se é que me entende. O que você teria que fazer é criar dois comandos, um para atualizar cada tabela, definir a propriedade AcceptChangesDuringUpdate do DataAdapter para false para que possa ser possível duas chamadas ao método Update() do DataAdaper seguidas sem que sejam alteradas automaticamente no DataSet as propriedades que dizem ao DataAdaper o que deve ser atualizado e finalmente invocar manualmente o método AcceptChanges() do DataSet quando as atualizações terminarem.

    Aqui um exemplo utilizando as tabelas Orders e Order Details do banco de exemplos Northwind (se não tiver o banco instalado e quiser testar o código, obtenha o script de geração no link). Declare no escopo da classe:

    private DataSet ds;        
    private SqlConnection cnn;        
    private SqlDataAdapter da;    
     

     

    Para preencher o DataSet e vinculá-lo a um DataGridView use este código:

    // String de conexão.        
    cnn = new SqlConnection("Data Source=.;Initial Catalog=Northwind;Integrated Security=SSPI;");        
           
    // Faz um Join nos dados das tabelas Orders e Order Details.        
    da = new SqlDataAdapter("SELECT * FROM Orders AS O, [Order Details] AS D WHERE O.OrderID = D.OrderID", cnn);        
           
    ds = new DataSet();        
           
    // Preenche um DataTable chamado "OrdersXOrderDetails"         
    // com os dados da consulta.        
    da.Fill(ds, "OrdersXOrderDetails");        
           
    dataGridView1.DataSource = ds.Tables["OrdersXOrderDetails"];       
     

     

    Depois de modificar no DataGridView os valores dos campos CustomerID da tabela Orders e Quantity da tabela Order Details, faça as atualizações na base de dados assim:

    // Comando para a atualização da tabela Orders.     
    SqlCommand cmdOrders = new SqlCommand("UPDATE Orders SET CustomerID = @CustomerID WHERE OrderID = @OrderID", cnn);     
    cmdOrders.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");     
    cmdOrders.Parameters.Add("@OrderID", SqlDbType.Int, 4, "OrderID");     
        
    // Comando para a atualização da tabela Order Details.     
    SqlCommand cmdDetails = new SqlCommand("UPDATE [Order Details] SET Quantity = @Quantity WHERE OrderID = @OrderID1 AND ProductID = @ProductID", cnn);     
    cmdDetails.Parameters.Add("@Quantity", SqlDbType.SmallInt, 2, "Quantity");     
    cmdDetails.Parameters.Add("@OrderID1", SqlDbType.Int, 4, "OrderID1");     
    cmdDetails.Parameters.Add("@ProductID", SqlDbType.Int, 4, "ProductID");     
        
    // Não queremos que o DataAdapter invoque automaticamente o método     
    // AcceptChanges() do DataSet. Queremos fazê-lo manualmnete.     
    da.AcceptChangesDuringUpdate = false;     
        
    // Definimos o comando de atualização da tabela Orders     
    // como o comando utilizado pelo DataAdapter para atualizações.     
    da.UpdateCommand = cmdDetails;     
    da.Update(ds, "OrdersXOrderDetails");     
    da.UpdateCommand = cmdOrders;     
    // Fazemos a atualização.     
    da.Update(ds, "OrdersXOrderDetails");     
        
        
    // Definimos o comando de atualização da tabela Order Details     
    // como o comando utilizado pelo DataAdapter para atualizações.     
    da.UpdateCommand = cmdDetails;     
    // Fazemos a atualização.     
    da.Update(ds, "OrdersXOrderDetails");     
        
    // Aceitamos as alterações feitas no DataSet depois das atualizações.     
    ds.AcceptChanges();    
     

     

    Alternativamente você poderia criar um único objeto Command contendo ambos os comandos de atualização a serem executados, isso possibilitaria permitir ao DataAdapter continuar a invocar o método AcceptChanges() do DataSet automaticamente. Nesse caso o último trecho de código poderia ser alterado para isto:

    // Criamos um objeto comando contendo os comando de atualização das tabelas Orders e Order Details.         
    SqlCommand cmd = new SqlCommand("UPDATE Orders SET CustomerID = @CustomerID WHERE OrderID = @OrderID; UPDATE [Order Details] SET Quantity = @Quantity WHERE OrderID = @OrderID1 AND ProductID = @ProductID", cnn);        
    cmd.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");        
    cmd.Parameters.Add("@OrderID", SqlDbType.Int, 4, "OrderID");        
    cmd.Parameters.Add("@Quantity", SqlDbType.SmallInt, 2, "Quantity");        
    cmd.Parameters.Add("@OrderID1", SqlDbType.Int, 4, "OrderID1");        
    cmd.Parameters.Add("@ProductID", SqlDbType.Int, 4, "ProductID");        
           
    // Executamos os comandos.        
    da.UpdateCommand = cmd;        
    da.Update(ds, "OrdersXOrderDetails");     
     

     

    Note que quando duas tabelas são jogadas num mesmo DataTable quaisquer nomes de campos idênticos, como OrderID no exemplo, serão diferenciados: observe que o campo OrderID da tabela Order Details foi modificado para OrderID1 para que seja diferente do campo OrderID da tabela Orders... Como eu disse, isso o que você quer fazer não constitui uma abordagem limpa e eu não a utilizaria. Provavelmente haverá bugs.

    O mínimo que você deveria fazer para um código decente, se quiser utilizar DataAdapters etc., seria a criação de um DataAdapter para interação com a tabela "utilizadores" e outro DataAdaper para interação com a tabela "filas". Preencha um DataTable para cada uma das tabelas com seus respectivos DataAdapters (os DataTables poderiam, claro, estar num mesmo DataSet), fazendo também a atualização das tabelas com seus respectivos DataAdapters. Para exibição e edição dos dados, use a abordagem de relacionamento Mestre/Detalhes com a utilização de dois DataGridViews, um para cada DataTable etc.

    Você encontrará exemplos de relacionamento Mestre/Detalhes nos links abaixo:

    http://www.macoratti.net/08/11/c_db_snc.htm

    http://msdn.microsoft.com/en-us/library/c12c1kx4(vs.80).aspx

     


    "Software Engineers don't have Trophy Wives; they have Presentation Layers."
    • Marcado como Resposta LuisMLPinto sexta-feira, 30 de janeiro de 2009 23:20
    • Editado Angus MacGyver sexta-feira, 30 de janeiro de 2009 23:56
    sexta-feira, 30 de janeiro de 2009 19:24
  • olá mais uma vez Angus, lá diz o povo, quem sabe sabe :). De facto parece-me que a opção master-detail me parece a melhor e é essa que vou seguir, de qualquer maneira vou tentar terminar a opção de um só Adapter, usando o código que colocou no post.

    muito obrigado pela ajuda.


    sou o rafael, sou de portugal e sou aluno de informatica
    sexta-feira, 30 de janeiro de 2009 23:20