Bug #48601 | MySqlCommandBuilder ReturnGeneratedIdentifiers Property does not exist | ||
---|---|---|---|
Submitted: | 6 Nov 2009 17:15 | Modified: | 24 Feb 2010 13:31 |
Reporter: | Matthew Bilek | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | Connector / NET Documentation | Severity: | S2 (Serious) |
Version: | 6.1 | OS: | Any |
Assigned to: | Tony Bedford | CPU Architecture: | Any |
Tags: | MySQL Connector/NET ReturnGeneratedIdentifiers |
[6 Nov 2009 17:15]
Matthew Bilek
[6 Nov 2009 17:52]
Tonci Grgin
Hi Matthew and thanks for your report. Alas, this is intentional and won't be supported any more... We are doing it like SqlClient does it. Command builder no longer attaches a "select last_inserted_id()" for you but you need to do it manually. Tony, please note this in manual, where appropriate, if needs be.
[11 Nov 2009 15:52]
Matthew Bilek
Tony, You commented "Command builder no longer attaches a "select last_inserted_id()" for you but you need to do it manually." Could you explain this in more detail. Thanks, Matthew
[5 Feb 2010 13:21]
Tony Bedford
The code below will return hero_id as NULL. So ReturnGeneratedIdentifiers is gone. How do we now obtain the last inserted id when using CommandBuilder? using System; using System.Text; using System.Data; using MySql.Data; using MySql.Data.MySqlClient; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { string connStr = "server=localhost;user=root;database=MarvelComics;port=3306;password=******;"; MySqlConnection conn = new MySqlConnection(connStr); try { Console.WriteLine("Connecting to MySQL..."); conn.Open(); string sql = "SELECT * FROM Heroes"; MySqlDataAdapter daHero = new MySqlDataAdapter(sql, conn); MySqlCommandBuilder cb = new MySqlCommandBuilder(daHero); MySqlCommand cmd = new MySqlCommand(); DataSet dsHero = new DataSet(); DataView dvHero = new DataView(); DataRow drRow; cmd.Connection = conn; cmd.CommandText = sql; daHero.SelectCommand = cmd; daHero.Fill(dsHero, "Heroes"); cb.DataAdapter = daHero; cb.DataAdapter.SelectCommand.CommandText = "SELECT * FROM Heroes"; cb.RefreshSchema(); dvHero = dsHero.Tables["Heroes"].DefaultView; drRow = dvHero.Table.NewRow(); drRow["first_name"] = "Tonci"; drRow["last_name"] = "Grgin"; dvHero.Table.Rows.Add(drRow); daHero.Update(dsHero, "Heroes"); System.Console.WriteLine("ID after update: " + drRow["hero_id"]); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } conn.Close(); Console.WriteLine("Done."); } } }
[5 Feb 2010 18:51]
Reggie Burnett
Tony You need to fetch the command from the commandbuilder. Like this: MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM test", c); MySqlCommandBuilder cb = new MySqlCommandBuilder(da); MySqlCommand insertCmd = cb.GetInsertCommand(); insertCmd.CommandText += ";SELECT last_insert_id()"; insertCmd.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord; da.InsertCommand = insertCmd;
[10 Feb 2010 17:14]
Tony Bedford
Changed the code as follows but still returning NULL for ID. Can anyone see where I'm going wrong please? Thanks! using System; using System.Text; using System.Data; using MySql.Data; using MySql.Data.MySqlClient; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { string connStr = "server=localhost;user=root;database=MarvelComics;port=3306;password=******;"; MySqlConnection conn = new MySqlConnection(connStr); try { Console.WriteLine("Connecting to MySQL..."); conn.Open(); string sql = "SELECT * FROM Heroes"; MySqlDataAdapter daHero = new MySqlDataAdapter(sql, conn); MySqlCommandBuilder cb = new MySqlCommandBuilder(daHero); MySqlCommand cmd = new MySqlCommand(); cmd.Connection = conn; cmd.CommandText = sql; MySqlCommand insertCmd = cb.GetInsertCommand(); insertCmd.CommandText = insertCmd.CommandText + ";SELECT last_insert_id()"; insertCmd.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord; daHero.InsertCommand = insertCmd; DataSet dsHero = new DataSet(); DataView dvHero = new DataView(); DataRow drRow; daHero.SelectCommand = cmd; daHero.Fill(dsHero, "Heroes"); cb.DataAdapter = daHero; daHero.SelectCommand.CommandText = "SELECT * FROM Heroes"; cb.RefreshSchema(); dvHero = dsHero.Tables["Heroes"].DefaultView; drRow = dvHero.Table.NewRow(); drRow["first_name"] = "Tonci"; drRow["last_name"] = "Grgin"; dvHero.Table.Rows.Add(drRow); daHero.Update(dsHero, "Heroes"); System.Console.WriteLine("ID after update: " + drRow["hero_id"]); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } conn.Close(); Console.WriteLine("Done."); } } }
[19 Feb 2010 19:33]
Reggie Burnett
Tony This is really caused by a problem in the .net framework. Essentially what happens is this. CommandBuilder hooks up to the DataAdapter.RowUpdating event handler (which means it will get called for every row). It examines the command object and, if it is the same referenced object, it essentially rebuilds the object (throwing away your command text mods). First, the thing to understand is that command builder is used by MSFT for generating SQL at design time not run time. They heavily discourage it's use in serious apps. The simple approach to solve this problem is simple to clone the command object so you have a different actual reference. Like this: dataAdapter.InsertCommand = cb.GetInsertCommand().Clone() This will work but since the command builder is still connected the RowUpdating event will still fire and performance will be hit. To stop that, once all your commands are hooked up you need to do this: cb.DataAdapter = null; The last thing you need to do is make sure the id that is returned by last_insert_id has the right name. There are two ways of connecting that value to the table but the easiest way is simple to give it the right name. Here is your sample modified to work correctly: string sql = "SELECT * FROM test"; MySqlDataAdapter daHero = new MySqlDataAdapter(sql, conn); MySqlCommandBuilder cb = new MySqlCommandBuilder(daHero); MySqlCommand insertCmd = cb.GetInsertCommand().Clone(); insertCmd.CommandText += ";SELECT last_insert_id() as hero_id"; insertCmd.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord; daHero.InsertCommand = insertCmd; // doing this unhooks the RowUpdating event handler cb.DataAdapter = null; DataTable dt = new DataTable(); daHero.Fill(dt); DataRow row = dt.NewRow(); row["first_name"] = "Tonci"; row["last_name"] = "Grgin"; dt.Rows.Add(row); daHero.Update(dt);
[24 Feb 2010 13:31]
Tony Bedford
Thanks Reggie. That worked. I have simplified the example, and updated the FAQ page on this in the main C/NET docs XML sources. Online docs should update in the next 24 hours or so.