none
Atualizar dados do Banco através do DataSet RRS feed

  • Pergunta

  • Ola pessoal, preciso atualizar o banco de dados (Insert, Update, Delete) atavez de um DataSet mas não estou conseguindo. Recebo a seguinte mensagem:

    Não há suporte para geração SQL dinâmica para UpdateCommand em SelectCommand que não retorne informações importantes de coluna.

    Veja como esta o meu codigo

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Data.OleDb;
    using Agili;

    namespace WindowsFormsApplication10
    {
        public partial class Form1 : Form
        {
            DataSet ds;
            OleDbDataAdapter da;
            _clConexaoBanco conexao;
            OleDbCommandBuilder cb;

            public Form1()
            {
                InitializeComponent();
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                conexao = new _clConexaoBanco();
               
                da = new OleDbDataAdapter("Select idTeste, nmTeste, vlTeste, dtCadastro From tblTeste",conexao.conexao);
                cb = new OleDbCommandBuilder(da);
                ds = new DataSet("Teste");
                da.FillSchema(ds, SchemaType.Mapped, "Teste");
                da.Fill(ds, "Teste");

                DataColumn[] dc = new DataColumn[1];
               
                dc[0] = ds.Tables[0].Columns["idTeste"];
                ds.Tables["Teste"].PrimaryKey = dc;

                da.InsertCommand = cb.GetInsertCommand();

        
                // Esta dando erro nesta linha
                da.UpdateCommand = cb.GetUpdateCommand();
                da.DeleteCommand = cb.GetDeleteCommand();          
            }

            private void btnInserir_Click(object sender, EventArgs e)
            {
                DataRow dr;

                dr = ds.Tables[0].NewRow();
               
                dr["idTeste"]    = txtId.Text;
                dr["nmTeste"]    = txtNome.Text;
                dr["vlTeste"]    = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;

                ds.Tables[0].Rows.Add(dr);
                da.Update(ds,"Teste");
            }

            private void btnAlterar_Click(object sender, EventArgs e)
            {
                DataRow dr;

                dr = ds.Tables["Teste"].Rows[0];

                dr.BeginEdit();
                //dr["idTeste"] = txtId.Text;
                dr["nmTeste"] = txtNome.Text;
                dr["vlTeste"] = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;
                dr.EndEdit();         
                da.Update(ds,"Teste");

            }

            private void btnExcluir_Click(object sender, EventArgs e)
            {
                ds.Tables[0].Rows[0].Delete();
                da.Update(ds);
            }
        }
    }

    A chave primaria da tabela é o campo idTeste.

    Qual é o erro?
    segunda-feira, 24 de agosto de 2009 17:04

Todas as Respostas

  • Verifique se o SELECT esta retornando todas as colunas pertinentes. Somente desta forma você consiguira.
    Binding you through life - Se serve, marque!!!
    segunda-feira, 24 de agosto de 2009 17:45
    Moderador
  • Sim, o select esta retornando todos os campos da tabela, o interessante é que consigo fazer o insert mas o update não. Veja como esta o código:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Data.OleDb;
    using Agili;

    namespace WindowsFormsApplication10
    {
        public partial class Form1 : Form
        {
            DataSet ds;
            OleDbDataAdapter da;
            _clConexaoBanco conexao;
            OleDbCommandBuilder cb;

            public Form1()
            {
                InitializeComponent();
            }

            private void Form1_Load(object sender, EventArgs e)
            {
                conexao = new _clConexaoBanco();
                da = new OleDbDataAdapter("Select idTeste, nmTeste, vlTeste, dtCadastro From tblTeste",conexao.conexao);
             
                ds = new DataSet("Teste");
                da.FillSchema(ds, SchemaType.Source, "Teste");
                cb = new OleDbCommandBuilder(da);
                          
                da.Fill(ds, "Teste");           

                //DataColumn[] dc = new DataColumn[1];           
                //dc[0] = ds.Tables[0].Columns["idTeste"];
                //ds.Tables["Teste"].PrimaryKey = dc;          

            }

            private void btnInserir_Click(object sender, EventArgs e)
            {
                DataRow dr;
                dr = ds.Tables[0].NewRow();
               
                dr["idTeste"]    = txtId.Text;
                dr["nmTeste"]    = txtNome.Text;
                dr["vlTeste"]    = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;

                ds.Tables[0].Rows.Add(dr);           

                da.Update(ds,"Teste");
            }

            private void btnAlterar_Click(object sender, EventArgs e)
            {
                DataRow dr;

                dr = ds.Tables["Teste"].Rows[0];

                dr.BeginEdit();
                //dr["idTeste"] = txtId.Text;
                dr["nmTeste"] = txtNome.Text;
                dr["vlTeste"] = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;
                dr.EndEdit();         
                da.Update(ds,"Teste");

            }

            private void btnExcluir_Click(object sender, EventArgs e)
            {
                ds.Tables[0].Rows[0].Delete();
                da.Update(ds);
            }
        }
    }

    segunda-feira, 24 de agosto de 2009 18:06
  • Tente fazer o seguinte, ao invez de nomear os campo use * assim garantimos que tudo esta sendo carregado.
    Tambem arrume a a propriedade do dataAdapter "MissingSchemaAction" para "AddWithKey".

    Se isso funcionar, remova o * e arrume as colunas de acordo com o que você realmente precisa.
    Binding you through life - Se serve, marque!!!
    segunda-feira, 24 de agosto de 2009 18:13
    Moderador
  • Fiz as mudanças que vc falou, mas agora ele esta dando esta mensagem de erro quando chamo o metodo Update do DataAdapter

    Não há suporte para geração SQL dinâmica para UpdateCommand em SelectCommand que não retorne informações importantes de coluna.


    segunda-feira, 24 de agosto de 2009 18:30
  • Marcio,
    Posso estar falando bobagem mas de acordo com http://msdn.microsoft.com/pt-br/library/system.data.oledb.oledbcommandbuilder.aspx 
    o comando dataAdapter.Update() não iria funcionar se vc nao tiver um CommandBuilder no código.

    Veja esse código tirado da página:
    public static DataSet UpdateRows(string connectionString,
        string queryString, string tableName)
    {
        DataSet dataSet = new DataSet();
        using (OleDbConnection connection = new OleDbConnection(connectionString))
        {
            OleDbDataAdapter adapter = new OleDbDataAdapter();
            adapter.SelectCommand = new OleDbCommand(queryString, connection);
            OleDbCommandBuilder cb = new OleDbCommandBuilder(adapter);
    
            connection.Open();
    
            adapter.Fill(dataSet, tableName);
    
            //code to modify data in DataSet here
    
            cb.GetDeleteCommand();
            //Without the OleDbCommandBuilder this line would fail
            adapter.Update(dataSet, tableName);
    
            connection.Close();
        }
        return dataSet;
    }
    Não sei como seu Insert está funcionando, mas enfim, tente criar um CommandBuilder e ver se dá certo!
    segunda-feira, 24 de agosto de 2009 18:36
  • Ola Reinaldo, eu estou usando um CommandBuilder sim.
    segunda-feira, 24 de agosto de 2009 18:40
  • verdade, não tinha visto!

    Entao acho que falta isso

    da.UpdateCommand = cb.GetUpdateCommand();

    segunda-feira, 24 de agosto de 2009 18:42
  • Quando fiz isso  (da.UpdateCommand = cb.GetUpdateCommand();)  ele me deu o seguinte erro ao executar esta linha:

    Não há suporte para geração SQL dinâmica para UpdateCommand em SelectCommand que não retorne informações importantes de coluna.

    O que pode ser?
    segunda-feira, 24 de agosto de 2009 18:47
  • da.UpdateCommand = new OledbCommand(String.Format("UPDATE tabela SET campo1={0}, campo2={1}, campo3={2} WHERE campoID={3}",dr["nmTeste"],dr["vlTeste"],dr["dtCadastro"],dr["idTeste"]));

    Não esqueça de fazer as tranformações ex: Convert.toDateTime(dr["dtCadastro"]) e etc
    edit: acho q não vai precisar faze os converts pq depois vai td como string


    Ve se dá certo
    segunda-feira, 24 de agosto de 2009 19:10
  • Ok Reinaldo, vou tentar aqui depois posto o resultado
    T+
    segunda-feira, 24 de agosto de 2009 19:28
  • Reinaldo testei aqui mas no meu caso é inviável esta tecnica pois a casos onde o dataset tem muitas alteraçoes, inclusões e deleçoes desta forma eu tenho que fazer um loop no dataset para saber o tipo de alteração e disparar o método adequado. Eu preciso usar uma forma mais automática ou seja quando eu executar o método Update do adapter ele aplica todas as alteraçoes no banco. Sei que preciso definir os comandos para insert, update e delete no adapter mas preciso que isso fique mais dinamico.

    Voce me entende ?
    terça-feira, 25 de agosto de 2009 13:26
  • Acredito que o problema esta na forma como a query de select foi definida, mas como não conseguimos decobrir o problem, defina a query de update na mão e atribua a mesma manualmente à propriedado do DataAdapter
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 18:39
    Moderador
  • Eu fiz assim, aparentemente não deu erro em nada, mas também atualizou nada no banco.

            private void btnAlterar_Click(object sender, EventArgs e)
            {
                string strConexao = "Provider=OraOLEDB.Oracle.1;Password=dbdsvphoenix;Persist Security Info=True;User ID=dbdsvphoenix;Data Source=PROD";
                OleDbConnection conexao = new OleDbConnection(strConexao);
                string strUpdate;

                da = new OleDbDataAdapter("Select idTeste, nmTeste, vlTeste, dtCadastro From tblTeste", conexao);
                ds = new DataSet("Teste");
                da.Fill(ds, "Teste");

                strUpdate = "Update tblTeste set nmTeste = @nmTeste, vlTeste = @vlTeste, dtCadastro = @dtCadastro Where idTeste = @idTeste";

                da.UpdateCommand = new OleDbCommand(strUpdate);
                da.UpdateCommand.Parameters.Add("@nmTeste", OleDbType.VarChar, 100, "nmTeste");
                da.UpdateCommand.Parameters.Add("@vlTeste", OleDbType.Double, 10, "vlTeste");
                da.UpdateCommand.Parameters.Add("@dtCadastro", OleDbType.Date, 15, "dtCadastro");
                da.UpdateCommand.Parameters.Add("@idTeste", OleDbType.Integer, 10, "idTeste");
                da.UpdateCommand.Connection = conexao;


                DataRow dr;
                dr = ds.Tables["Teste"].Rows[0];

                dr.BeginEdit();
                //dr["idTeste"] = txtId.Text;
                dr["nmTeste"] = txtNome.Text;
                dr["vlTeste"] = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;
                dr.EndEdit();
                ds.AcceptChanges();
                da.Update(ds,"Teste");           
            }






    terça-feira, 25 de agosto de 2009 19:02
  • Inverta as ultimas duas linhas do codigo, você esta aceitando as mudanças antes de envialas. Ou seja quando você envia, ele simplesmente acha que não existem mudanças.
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 19:04
    Moderador
  • Outra coisa a ser notada, que eu não havia notado, você esta usando Oracle como base de dados e por default Oracle não faz commit, ou seja você que tem que fazer.
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 19:06
    Moderador
  • Humm Ok, vou acertar aqui
    terça-feira, 25 de agosto de 2009 19:15
  • Ha, mas por que o insert funciona, veja o código:

            private void btnInserir_Click(object sender, EventArgs e)
            {
                DataRow dr;
                dr = ds.Tables[0].NewRow();
               
                dr["idTeste"]    = txtId.Text;
                dr["nmTeste"]    = txtNome.Text;
                dr["vlTeste"]    = txtValor.Text;
                dr["dtCadastro"] = txtData.Text;

                ds.Tables[0].Rows.Add(dr);           

                da.Update(ds,"Teste");


    terça-feira, 25 de agosto de 2009 19:16
  • Boa pergunta

    Você testou o update com as mundaças e continua não funcionando?


    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 19:19
    Moderador
  • Quando fiz a inversão das linas como voce disse, ele deu este erro:

    Não há suporte para geração SQL dinâmica para UpdateCommand em SelectCommand que não retorne informações importantes de coluna.


    terça-feira, 25 de agosto de 2009 19:22
  • Muito estranho tudo isso.

    Você ja tentou ao invez de fazer na mão usar o wizard do Grid?

    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 19:26
    Moderador
  • Não estou usando Grid, tenho uma tela e pego os dados dos TextBoxe
    terça-feira, 25 de agosto de 2009 19:27
  • Pergunta basica, mas extramamente pertinente.

    A tabela de qual você esta puxando os dados tem um chave primaria, e esta esta sendo retornado no select?
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 20:10
    Moderador
  • Sim, ela possui e no select ela esta vindo

    A minha tabela é esta:

    IDTESTE    NUMBER(10)     -> Chave Primaria
    NMTESTE    VARCHAR2(50) Y                        
    VLTESTE    NUMBER(10,2) Y                        
    DTCADASTRO DATE         Y   

    eo select que estou passando para o Adapter é este:

    Select idTeste, nmTeste, vlTeste, dtCadastro From Teste
    terça-feira, 25 de agosto de 2009 20:15
  • O que esta acontecendo aparentemente é que quando o update vai acontecer ele não consegue definir qual é a chave primaria e sem a chave primaria ele não pode garantir que apenas um registro vai ser alterado então ele falha.

    Tente o seguinte,

    Após preexncher sua tabela no DataSet defina manualmente a coluna da chave primaria.

    Algo assim

    Table oneTable = ds.Tables[0]
    oneTable.PrimaryKey = oneTable.Columns["idTeste"]
    Acho que é assim, fiz o codigo fora do VS, então testa ae.
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 20:21
    Moderador
  • Fiz como voce disse mas Infelizmente não funcionou.
    terça-feira, 25 de agosto de 2009 20:29
  • Manda o codigo pra mim.

    Ahhhhhhhh!!!
    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 20:31
    Moderador
  • Ok, qual é o seu email?
    terça-feira, 25 de agosto de 2009 20:33
  • Ok, ja te mandei

    Obrigado por enquanto
    terça-feira, 25 de agosto de 2009 20:41
  • Vamos la,


    cb = new OleDbCommandBuilder(da);
    da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    da.FillSchema(ds, SchemaType.Source);
    
    DataColumn[] dc = new DataColumn[1];
    dc[0] = ds.Tables[0].Columns["idTeste"];
    ds.Tables["Teste"].PrimaryKey = dc;   
    
    da.Fill(ds, "Teste");
    Tente alterar desta maneira.


    Veja tambem o que achei na documentação

    Adds the necessary columns and primary key information to complete the schema. For more information about how primary key information is added to a DataTable, see FillSchema.To function properly with the .NET Framework Data Provider for OLE DB, AddWithKey requires that the native OLE DB provider obtains necessary primary key information by setting the DBPROP_UNIQUEROWS property, and then determines which columns are primary key columns by examining DBCOLUMN_KEYCOLUMN in the IColumnsRowset. As an alternative, the user may explicitly set the primary key constraints on each DataTable. This ensures that incoming records that match existing records are updated instead of appended. When using AddWithKey, the .NET Framework Data Provider for SQL Server appends a FOR BROWSE clause to the statement being executed. The user should be aware of potential side effects, such as interference with the use of SET FMTONLY ON statements. See SQL Server Books Online for more information.


    Binding you through life - Se serve, marque!!!
    terça-feira, 25 de agosto de 2009 21:01
    Moderador
  • Bom dia  ViewState

    Refiz o código como voce sugeriu mas o erro continua, na verdade eu ja tinha feito isso como voce pode ver no código acima e mesmo assim continua dando a mensagem de erro:

    Não há suporte para geração SQL dinâmica para UpdateCommand em SelectCommand que não retorne informações importantes de coluna.

    Não sei mais o que fazer, ja estou ficando louco hahaha, so com bom humor mesmo.

    vou continuar pesquisando e testando mas estou chegando a conclusão que isso não vai ser possível.

    se voce tiver outra sugestão estou aceitando.
    quarta-feira, 26 de agosto de 2009 11:42
  • Estou pensando em usar LINQ, o que vocês acham ?
    Será que resolveria o meu problema ?
    quarta-feira, 26 de agosto de 2009 16:34
  • Se o provider funcionar direitinho pra Oracle manda bala,


    http://www.codeplex.com/LinqToOracle


    Tai o link.


    Binding you through life - Se serve, marque!!!
    quarta-feira, 26 de agosto de 2009 16:37
    Moderador
  • Você fez exatamente na ordem que eu fiz?
    Binding you through life - Se serve, marque!!!
    quarta-feira, 26 de agosto de 2009 16:38
    Moderador
  • Sim, na mesma sequencia
    quarta-feira, 26 de agosto de 2009 16:47
  • O meu projeto é para multi-banco, o LINQ suporta esta característica?
    quarta-feira, 26 de agosto de 2009 16:49
  • Não, Linq travalho com sabores, LINQ to SQL, LINQ to ORACLE, LINQ to Entities e assim vai.

    Um sugestão, é trabalhar com commands, esquece o DataAdapter e DataSet, faça as coisa na mão. Ou use algo como NHibernate, ou CodeSmith pra gerar seu codigo.
    Binding you through life - Se serve, marque!!!
    quarta-feira, 26 de agosto de 2009 16:51
    Moderador