none
probleme : La génération SQL dynamique n'est pas prise en charge pour un SelectCommand qui ne retourne pas des informations de table de base. RRS feed

  • Question

  • bonjour,

    dans mon exercice asp avec c# j'utilise un gridview et je veux inserer des donnees dans la base de donnees en mode deconnectéet je veux utiliser le commandbuilder pour economiser le travail :

     public void affichage_inserer(string tit, string sold)
        {
            conn = new OleDbConnection(
                @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\admin\Documents\Visual Studio 2010\WebSites\TpCompteModeDeconnecté\App_Data\baseCompte.accdb");
    
            OleDbDataAdapter adapter = new OleDbDataAdapter(
            "SELECT '' as [id_compte], '' as [titulaire],'' as [solde] from Compte UNION SELECT [id_compte],[titulaire], [solde] FROM [Compte]", conn);
            OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter);
            builder.QuotePrefix = "[";
            builder.QuoteSuffix = "]";
            
            DataSet custDS = new DataSet();
    
            conn.Open();
            adapter.Fill(custDS, "Compte");
    
            // Code to modify data in the DataSet here.
            DataRow contactRow = custDS.Tables[0].NewRow();
            contactRow["titulaire"] = "travail   ";
            contactRow["solde"] = "10090";
            custDS.Tables[0].Rows.Add(contactRow); //Ajoute la nouvelle ligne au dataSet courant
    
            // Without the SqlCommandBuilder, this line would fail.
            adapter.Update(custDS, "Compte");
            conn.Close();
            GridView1.DataSource = dsCompte;
            GridView1.DataBind();
        }

    et l'erreur :

    La génération SQL dynamique n'est pas prise en charge pour un SelectCommand qui ne retourne pas des informations de table de base.

    alors si j'execute le meme code dans un programme c# bureau (pas web) ca marche

    est ce que vous avez une idée

    merci bien


    mardi 8 mai 2012 23:49

Réponses

  • Bonjour,

    Je vois que dans la branche "Delete" on utilise Remove (qui supprime la ligne de la DataTable on donc on n'a plus aucune trace de son existence) au lieu de Delete qui va la marquer comme supprimée (donc dans le premier cas GetChanges retourne null car aucune ligne présente dans le DataTable n'a été "modifiée" car la ligne en question a été réellement supprimée du DataTable).

    Accessoirement le DataTable semble juste destinée à lancer au final les différentes commandes. Dans ce cas, il ne me semble pas vraiment utile et exécuter directement les commandes via OleDbCommand.ExecuteNonQuery serait sans doute plus simple...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    • Marqué comme réponse angelo marco vendredi 11 mai 2012 09:40
    vendredi 11 mai 2012 08:57
    Modérateur

Toutes les réponses

  • Bonjour,

    Il n'est pas possible de générer un commande INSERT/UPDATE/DELETE à partir d'une commande contenant un opérateur ensembliste (UNION/INTERSECT) ou une jointure.

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    mercredi 9 mai 2012 08:21
    Modérateur
  • bonjour,

    merci pour la reponse

    mais comment je vais faire puisque je veux avoir une ligne vide avant l'affichage des enregistrements juste pour l'utiliser pour l'insertion

    sachant qu'il est strictement demandé de travailler avec le mode deconnecté

    car dans le mode connecté j'ai reussi a le faire

    merci bien

    mercredi 9 mai 2012 21:26
  • Bonjour,

    Vous devez exécuter deux requêtes INSERT ou UPDATE ou DELETE à la main.
    Vous n'avez pas d'autres choix...

    Par contre au lieu d'utiliser l'opérateur UNION pour faire du bricolage ("juste avoir un ligne vide"). Ne pouvez-vous pas faire une requête simple SELECT et si le résultat de cette requête est vide (c'est à dire que votre DataTable.Rows.Count == 0), alors vous créez une ligne vide....

    Ainsi vous pourrez avoir les commandes INSERT/UPDATE/DELETE automatiquement générées.

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    jeudi 10 mai 2012 07:29
    Modérateur
  • Bonjour,

    Oui ou lisez simplement les lignes de votre base avec un simple SELECT et ajouter cette ligne vierge dans le DataTable comme vous le faites d'ailleurs déjà pour la ligne travail, 10090...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    jeudi 10 mai 2012 10:49
    Modérateur
  • bonjour,

    j'ai reussi enfin a inserer et modifier avec une methode ou je fais tous a la main comme vous avez dis Gilles,

    et en ce qui concerne la requette union : je l'ai mis dans une methode init et je l'appelle aprres chaque maj

    mais maintenant un probleme dans la suppression : voila le code de la methode :

    private static void MergeIdentityColumns(OleDbConnection connection, int choix)
        {
            using (connection)
            {
                
                // Create a DataAdapter based on a SELECT query.
                daCompte = new OleDbDataAdapter(
                 "SELECT id_compte, titulaire, solde FROM Compte",
                 connection);
                switch (choix)
                {
                    case 0:
                        {
                            // Create the INSERT command for the new category.
                            daCompte.InsertCommand = new OleDbCommand(
                              "INSERT INTO Compte (titulaire, solde) Values(?,?)", connection);
                            daCompte.InsertCommand.CommandType = CommandType.Text;

                            // Add the parameter for the titulaire.
                            daCompte.InsertCommand.Parameters.Add(
                              "@titulaire", OleDbType.VarWChar, 15, "titulaire");
                            daCompte.InsertCommand.Parameters.Add(
                              "@titulaire", OleDbType.Integer, 15, "solde");
                            daCompte.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;

                            // Create a DataTable
                            DataTable comptes = new DataTable();

                            // Create the id_compte column and set its auto
                            // incrementing properties to decrement from zero.
                            DataColumn column = new DataColumn();
                            column.DataType = System.Type.GetType("System.Int32");
                            column.ColumnName = "id_compte";
                            column.AutoIncrement = true;
                            column.AutoIncrementSeed = 0;
                            column.AutoIncrementStep = -1;
                            comptes.Columns.Add(column);

                            // Create the titulaire column.
                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "titulaire";
                            comptes.Columns.Add(column);

                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "solde";
                            comptes.Columns.Add(column);

                            // Set the primary key on id_compte.
                            DataColumn[] pKey = new DataColumn[1];
                            pKey[0] = comptes.Columns["id_compte"];
                            comptes.PrimaryKey = pKey;

                            // Fetch the data and fill the DataTable
                            daCompte.Fill(comptes);

                            // Add a new row.
                            DataRow newRow = comptes.NewRow();
                            newRow["titulaire"] = "New Category";
                            newRow["solde"] = "8894";
                            comptes.Rows.Add(newRow);

                            // Add another new row.
                            DataRow newRow2 = comptes.NewRow();
                            newRow2["titulaire"] = "Another New Category";
                            newRow2["solde"] = "2324";
                            comptes.Rows.Add(newRow2);

                            // Add changed rows to a new DataTable that will be
                            // used to post the inserts to the database.
                            DataTable dataChanges = comptes.GetChanges();

                            // Include an event to fill in the Autonumber value.
                            daCompte.RowUpdated +=
                                new OleDbRowUpdatedEventHandler(OnRowUpdated);

                            // Update the database, inserting the new rows.
                            daCompte.Update(dataChanges);


                            // Merge the two DataTables.
                            comptes.Merge(dataChanges);

                            // Commit the changes.
                            comptes.AcceptChanges();

                            //dsCompte.Tables.Remove(dsCompte.Tables[0]);
                            //dsCompte.Tables.Add(comptes);
                        } break;
                    case 1:
                        {
                            // Create the INSERT command for the new category.
                            daCompte.UpdateCommand = new OleDbCommand(
                              "UPDATE Compte set titulaire = ? , solde = ? where id_compte = 90 ", connection);
                            daCompte.UpdateCommand.CommandType = CommandType.Text;


                            daCompte.UpdateCommand.Parameters.Add(
                              "@titulaire", OleDbType.VarWChar, 15, "titulaire");
                            daCompte.UpdateCommand.Parameters.Add(
                              "@solde", OleDbType.Integer, 15, "solde");
                            daCompte.UpdateCommand.UpdatedRowSource = UpdateRowSource.Both;

                            // Create a DataTable
                            DataTable comptes = new DataTable();

                            // Create the id_compte column and set its auto
                            // incrementing properties to decrement from zero.
                            DataColumn column = new DataColumn();
                            column.DataType = System.Type.GetType("System.Int32");
                            column.ColumnName = "id_compte";
                            column.AutoIncrement = true;
                            column.AutoIncrementSeed = 0;
                            column.AutoIncrementStep = -1;
                            comptes.Columns.Add(column);

                            // Create the titulaire column.
                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "titulaire";
                            comptes.Columns.Add(column);

                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "solde";
                            comptes.Columns.Add(column);

                            // Set the primary key on id_compte.
                            DataColumn[] pKey = new DataColumn[1];
                            pKey[0] = comptes.Columns["id_compte"];
                            comptes.PrimaryKey = pKey;

                            // Fetch the data and fill the DataTable
                            daCompte.Fill(comptes);

                            DataRow contactRow = comptes.Rows.Find("91");
                            //On signale le début de l'édition de la ligne
                            contactRow.BeginEdit();

                            contactRow["titulaire"] = "encoreencore";
                            contactRow["solde"] = "800";
                            //Fin de l'édition du contactRow
                            contactRow.EndEdit();
                            DataTable dataChanges = comptes.GetChanges();

                            // Include an event to fill in the Autonumber value.
                            daCompte.RowUpdated +=
                                new OleDbRowUpdatedEventHandler(OnRowUpdated);

                            // Update the database, inserting the new rows.
                            daCompte.Update(dataChanges);


                            // Merge the two DataTables.
                            comptes.Merge(dataChanges);

                            // Commit the changes.
                            comptes.AcceptChanges();

                            //dsCompte.Tables.Remove(dsCompte.Tables[0]);
                            //dsCompte.Tables.Add(comptes);

                        } break;
                    case 2:
                        {

                            // Create the INSERT command for the new category.
                            daCompte.DeleteCommand = new OleDbCommand(
            "DELETE FROM Compte WHERE id_compte = 90", connection);
                           /* daCompte.DeleteCommand.Parameters.Add("@id_compte",
            OleDbType.Char, 5, "id_compte").SourceVersion =
            DataRowVersion.Original;

                            daCompte.DeleteCommand.CommandType = CommandType.Text;
                            */
                            daCompte.DeleteCommand.UpdatedRowSource = UpdateRowSource.Both;

                            // Create a DataTable
                            DataTable comptes = new DataTable();

                            // Create the id_compte column and set its auto
                            // incrementing properties to decrement from zero.
                            DataColumn column = new DataColumn();
                            column.DataType = System.Type.GetType("System.Int32");
                            column.ColumnName = "id_compte";
                            column.AutoIncrement = true;
                            column.AutoIncrementSeed = 0;
                            column.AutoIncrementStep = -1;
                            comptes.Columns.Add(column);

                            // Create the titulaire column.
                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "titulaire";
                            comptes.Columns.Add(column);

                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "solde";
                            comptes.Columns.Add(column);

                            // Set the primary key on id_compte.
                            DataColumn[] pKey = new DataColumn[1];
                            pKey[0] = comptes.Columns["id_compte"];
                            comptes.PrimaryKey = pKey;

                            // Fetch the data and fill the DataTable
                            daCompte.Fill(comptes);
                            
                            DataRow contactRow = comptes.Rows.Find(90);
                            
                            comptes.Rows.Remove(contactRow);
                            DataTable dataChanges = comptes.GetChanges();
                            

                            // Include an event to fill in the Autonumber value.
                            daCompte.RowUpdated +=
                                new OleDbRowUpdatedEventHandler(OnRowUpdated);

                            // Update the database, inserting the new rows.
                            daCompte.Update(comptes);


                            // Merge the two DataTables.
                            comptes.Merge(dataChanges);

                            // Commit the changes.
                            comptes.AcceptChanges();

                            //dsCompte.Tables.Remove(dsCompte.Tables[0]);
                            //dsCompte.Tables.Add(comptes);

                        }break;

                }
                
            }
        }


    et le probleme c'est dans cette ligne  :   daCompte.Update(dataChanges)

    il me dis : 

    L'argument 'table' ne peut pas être null.
    Nom du paramètre : table

    sachant que j'ai modifier la table en supprimant une ligne

    avez vous une idée ou une rectification du code ou ...

    merci bien





    vendredi 11 mai 2012 05:01
  • Bonjour,

    Essayez de corriger le code suivant :

    DataTable dataChanges = comptes.GetChanges(DataRowState.Deleted);

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    vendredi 11 mai 2012 07:16
    Modérateur
  • j'ai corrigé

    mais malheureusement : la meme erreur dans le mme endroit

    vendredi 11 mai 2012 08:14
  • Bonjour,

    Je vois que dans la branche "Delete" on utilise Remove (qui supprime la ligne de la DataTable on donc on n'a plus aucune trace de son existence) au lieu de Delete qui va la marquer comme supprimée (donc dans le premier cas GetChanges retourne null car aucune ligne présente dans le DataTable n'a été "modifiée" car la ligne en question a été réellement supprimée du DataTable).

    Accessoirement le DataTable semble juste destinée à lancer au final les différentes commandes. Dans ce cas, il ne me semble pas vraiment utile et exécuter directement les commandes via OleDbCommand.ExecuteNonQuery serait sans doute plus simple...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    • Marqué comme réponse angelo marco vendredi 11 mai 2012 09:40
    vendredi 11 mai 2012 08:57
    Modérateur
  • merci pour les idees

    mais la version mode connecté est deja faite

    maintenant je dois tous faire en mode deconnecté

    j'ai essayé delete mais il n'existe pas une methode comptes.Rows.delete(..)

    vendredi 11 mai 2012 09:20
  • Bonjour,

    Il suffit de faire :

    contactRow.Delete(); 

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    vendredi 11 mai 2012 09:28
    Modérateur
  • je vous remercie bien Gilles et Patrices

    l'astuce c'est le delete de Patrices :

    Je vois que dans la branche "Delete" on utilise Remove (qui supprime la ligne de la DataTable on donc on n'a plus aucune trace de son existence) au lieu de Delete qui va la marquer comme supprimée (donc dans le premier cas GetChanges retourne null car aucune ligne présente dans le DataTable n'a été "modifiée" car la ligne en question a été réellement supprimée du DataTable).

    enfin tous a marché

    bien voila le code finale

    "si vous avez qlq choses pour le rendre un peu plus beau je serai ravi"

    case 2:
                        {

                            // Create the INSERT command for the new category.
                            daCompte.DeleteCommand = new OleDbCommand(
            "DELETE FROM Compte WHERE id_compte = 218", connection);

                            daCompte.DeleteCommand.UpdatedRowSource = UpdateRowSource.Both;

                            // Create a DataTable
                            DataTable comptes = new DataTable();

                            // Create the id_compte column and set its auto
                            // incrementing properties to decrement from zero.
                            DataColumn column = new DataColumn();
                            column.DataType = System.Type.GetType("System.Int32");
                            column.ColumnName = "id_compte";
                            column.AutoIncrement = true;
                            column.AutoIncrementSeed = 0;
                            column.AutoIncrementStep = -1;
                            comptes.Columns.Add(column);

                            // Create the titulaire column.
                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "titulaire";
                            comptes.Columns.Add(column);

                            column = new DataColumn();
                            column.DataType = System.Type.GetType("System.String");
                            column.ColumnName = "solde";
                            comptes.Columns.Add(column);

                            // Set the primary key on id_compte.
                            DataColumn[] pKey = new DataColumn[1];
                            pKey[0] = comptes.Columns["id_compte"];
                            comptes.PrimaryKey = pKey;

                            daCompte.Fill(comptes);
                            
                            DataRow contactRow = comptes.Rows.Find(218);
                            contactRow.Delete();
                            daCompte.Update(comptes);
                            comptes.AcceptChanges();
                        }break;

    vendredi 11 mai 2012 09:39
  • Dans les 3 cas, on charge (toutes ?) les données dans le DataTable avant de faire une seule modification dessus pour au final l'envoyer tout de suite vers la base de données ce qui ne me semble pas vraiment correspondre à la notion de mode déconnecté.

    Pour moi, qq chose de plus représentatif serait, par exemple dans une appli Windows, de récupérer les données dans un DataTable. Via une UI, l'utilisateur va alors faire toutes les modifications qu'il souhaite pendant plusieurs minutes et le Update final va automatiquement déclencher les delete/insert/update correspondant qui là ont donc effectivement été clairement différés. Et éventuellement les données mises à jour continuent à être utilisées si l'utilisateur relance un cycle de modifications.

    Dans le cas présent, on charge les données, on les modifie et on mets à jour la base immédiatement ce qui ne me semble pas vraiment correspondre à un mode déconnecté (qui pour moi serait plutôt l'accumulation de plusieurs modifications successives qui sont envoyées ultérieurement vers la base de données).

    Sinon le code actuel doit pouvoir être simplifié car la requête UNION a disparu donc le OleDbCommandBuilder doit-être à nouveau utilisable.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    vendredi 11 mai 2012 11:13
    Modérateur
  • Pour moi, qq chose de plus représentatif serait, par exemple dans une appli Windows, de récupérer les données dans un DataTable. Via une UI, l'utilisateur va alors faire toutes les modifications qu'il souhaite pendant plusieurs minutes et le Update final va automatiquement déclencher les delete/insert/update correspondant qui là ont donc effectivement été clairement différés. Et éventuellement les données mises à jour continuent à être utilisées si l'utilisateur relance un cycle de modifications.

    la je suis avec vous mais malheureusemnt je dois passer a autre chose, mais puisque cela marche c'est facile de faire qlq modifs pour arriver a ca

    cancernant le commandbuilder : je pense que ca ne va pas marché car la table se caracterise par une clé primaire et auto-increment ce que la commandbuilder ne peut pas gerer et jai trouvé ca mentionné dans la doc lorsqu'on parle des limites de commandbuilder

    aussi avant de finir si vous pouvez m'indiquer comment convertir le provider qui contient le chemin absolue vers la base de donnees en relative pour que je puisse exporter le siteweb asp.net avec t ces fichiers et le destinataire il lui suffir de l'ouvrir dans vs2010 ou vs2008

    et merci



    vendredi 11 mai 2012 11:22
  • J'avoue que cela fait un certain temps que je n'utilise plus les datatables. Si la clé primaire est définie dans la base je pense que c'est ok (sinon le commandbuilder ne peut JAMAIS être utilisé car toutes les tables ont normalement une clé primaire). Il reste possible que le auto increment pose problème (mais c'est peut-être qq chose à faire en plus sur le datatable ?). Ici je ne vois pas l'intérêt du mode déconnecté par rapport au mode déconnecté que vous avez donc fait précédemment. Mais bon laissons cela de côté...

    Pour le dernier point, il existe un "placeholder" DataDirectory qui pointe par défaut, pour une appli web, vers le dossier App_Data du site. Donc :

     @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\baseCompte.accdb"

    devrait être ok. Voir http://msdn.microsoft.com/fr-fr/library/cc716756(v=vs.110).aspx à la fin...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    vendredi 11 mai 2012 11:54
    Modérateur
  • apres qlq reflex j'ai conclu que je doix ajouter un boutton "refresh database"

    et que les enregistremenetsne ne s'effectuent que sur le datatable

    et la source de donnees ne se met ajour qu'apres le clic sur ce boutton

    donc pour cela lors d'une insertion je ne modifie que le datatable puis je rafraichie le gridview mais le probleme c'est que le gridview ne se rafraichit pas dans la page web : la nouvelle ligne ne s'ajoute pas

    voila le code ::

     DataRow newRow = dsCompte.NewRow();
                            newRow["titulaire"] = titulaire;
                            try
                            {
                                newRow["solde"] = solde;
                            }
                            catch (Exception e)
                            {
                                Page.ClientScript.RegisterClientScriptBlock(GetType(), "alert not loggued",
            "alert('Veuillez entrer une valeur entière pour l'attribut solde ! ');", true);
                                return;
                            }
                            
                            
                            dsCompte.Rows.Add(newRow);
                            Label1.Text = "nbre apres : " + dsCompte.Rows.Count;
                            //GridView1.
                            //GridView1.DataSource = dsCompte;
                            GridView1.DataBind();

    j'ai essayé ce qui est en comentaire mais ps de resutat

    est ce que vous avez une idée

    merci

    vendredi 11 mai 2012 15:16
  • Comme cette question est déjà marquée comme répondue, le 2ème sujet passe sans doute plus inaperçu. Quand on passe d'un sujet à un autre, le mieux est sans doute de créer une nouvelle question séparée.

    Dans quel évènement se trouve ce code ? Y a t'il un autre endroit où la GridView est "bindée" ?

    Il faut bien comprendre que la page est recrée de A à Z à chaque fois ou alors c'est peut-être un problème dans la gestion du cycle de vie de la page.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    mardi 15 mai 2012 07:57
    Modérateur
  • oui vous avez raison

    j'aurai du crée un autre sujet

    je m'excuse

    concernant le probleme mnt ca marche

    et merci

    mercredi 16 mai 2012 09:38