获取OleDbCommandBuilder生成的SQL命令

我使用OleDbDataAdapter和OleDbCommandBuilder用数据库内容填充DataSet对象,然后根据我在DataSet中所做的更改来更新数据库。 问题是我得到了exception:“并发冲突:UpdateCommand影响了预期的1条记录中的0条”。 我找到了这个错误的解释:

因为记录在从SELECT语句返回后可能已被修改,但在发出UPDATE或DELETE语句之前,自动生成的UPDATE或DELETE语句包含WHERE子句,指定仅在包含所有原始行的情况下才更新行值并且尚未从数据源中删除。 如果自动生成的更新尝试更新已删除的行或不包含DataSet中找到的原始值,则该命令不会影响任何记录,并且会引发DBConcurrencyException。

这意味着自动生成的UPDATE命令会影响数据库中的0行。 我使用paradox(db-file)数据库,除了我之外没有人改变它。 我猜我的程序在某处改变了同一行两次。 我想通过手动执行所有生成的查询来调试我的程序,并找到哪一个不影响任何行(因为实际上我非常确定所有更改只进行一次而且bug在其他地方)))。 是否可以手动运行自动生成的命令?

我的代码太大而且很复杂,不能在这里发布,但通常它的工作方式是这样的(我做了一个工作项目并从那里开始)

using System; using System.Data; using System.Windows.Forms; using System.Data.OleDb; namespace OleDBCommandBuilder { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { string cs = @"Provider=Microsoft.Jet.OLEDB.4.0;"; cs += @"Data Source=C:\FOLDER\1\SPR_KMZ\;"; cs += @"Extended Properties=Paradox 5.x;"; OleDbConnection Connection = new OleDbConnection(); Connection.ConnectionString = cs; try { Connection.Open(); } catch (Exception ex) { MessageBox.Show("Error openning database! " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } string SQLQuery = "SELECT * FROM SPR_KMZ WHERE REZ0"; DataSet SPR_KMZ = new DataSet(); OleDbDataAdapter DataAdapter = new OleDbDataAdapter(); DataAdapter.SelectCommand = new OleDbCommand(SQLQuery, Connection); OleDbCommandBuilder builder = new OleDbCommandBuilder(DataAdapter); try { DataAdapter.Fill(SPR_KMZ); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(String.Format("Error \n{0}\n{1}", ex.Message, SQLQuery)); Environment.Exit(0); } DataRow[] SPR_KMZ_rows = SPR_KMZ.Tables[0].Select("Fkmz=10000912 AND REZ=1"); foreach (DataRow SPR_KMZ_row in SPR_KMZ_rows) { SPR_KMZ_row["DN"] = Convert.ToDateTime("30.12.1899");//26.12.2008 SPR_KMZ_row["Price"] = Convert.ToDouble(0);//168,92 } DataAdapter.Update(SPR_KMZ); System.Windows.Forms.MessageBox.Show("Success!"); Environment.Exit(0); } } } 

PS以前它更新了没有并发exception的数据库,但是经过大量的更改(为了调试原因我长时间注释了“DataAdapter.Update(SPR_KMZ);”这一行,所以我不知道这个错误究竟何时开始投掷)

PSS我的代码中没有INSERT或DELETE,只有UPDATE …

<>

我发现问题是什么:如果“DN”字段具有NULL值,那么在更改它之后,自动生成的UPDATE语句不会影响任何内容,显然是因为“DN”包含在主键和命令构建器中并没有期望主键字段具有NULL值(谁曾经))),毫不奇怪这个引擎被称为“Paradox”)))

这就是为什么

 CommandBuilder.GetUpdateCommand().CommandText 

在“DN”字段的where子句中有这种模式:

 ... WHERE ((REZ = ?) AND (DN = ?) AND ... 

可空字段的描述如下:

 ... AND ((? = 1 AND Price IS NULL) OR (Price = ?)) AND ((? = 1 AND Nmed IS NULL) OR (Nmed = ?)) AND ... 

PSSS嘿,我可以尝试手动设置UpdateCommand来解决这个问题!)))

以下是我设法手动设置UpdateCommand的方法,甚至为正在执行的每个UPDATE命令获取SQL代码!(或多或少))。 调试时非常有用 – 我可以看到在DataAdapter.Update(DBDataSet)命令期间无法执行的SQL查询。

 public void Update(DataSet DBDataSet) { DataAdapter.RowUpdating += before_update; DataAdapter.Update(DBDataSet); } public void before_update(object sender, EventArgs e) { //Convert EventArgs to OleDbRowUpdatingEventArgs to be able to use OleDbCommand property System.Data.OleDb.OleDbRowUpdatingEventArgs oledb_e = (System.Data.OleDb.OleDbRowUpdatingEventArgs) e; //Get query template string cmd_txt = oledb_e.Command.CommandText; //Modify query template here to fix it //cmd_txt = cmd_txt.Replace("table_name", "\"table_name\""); //fill tamplate with values string cmd_txt_filled = cmd_txt; foreach(System.Data.OleDb.OleDbParameter par in oledb_e.Command.Parameters) { string par_type = par.DbType.ToString(); string string_to_replace_with = ""; if (par.Value.GetType().Name == "DBNull") { string_to_replace_with = "NULL"; } else { if (par_type == "Int32") { par.Size = 4; string_to_replace_with=Convert.ToInt32(par.Value).ToString(); } else if (par_type == "Double") { par.Size = 8; string_to_replace_with=Convert.ToDouble(par.Value).ToString().Replace(",","."); } else if (par_type == "DateTime") { par.Size = 8; /* In Paradox SQL queries you can't just specify the date as a string, * it will result in incompatible types, you have to count the days * between 30.12.1899 and the required date and specify that number */ string_to_replace_with = DateToParadoxDays(Convert.ToDateTime(par.Value).ToString("dd.MM.yyyy")); } else if (par_type == "String") { string_to_replace_with = '"' + Convert.ToString(par.Value) + '"'; } else { //Break execution if the field has a type that is not handled here System.Diagnostics.Debugger.Break(); } } cmd_txt_filled = ReplaceFirst(cmd_txt_filled, "?", string_to_replace_with); } cmd_txt_filled = cmd_txt_filled.Replace("= NULL", "IS NULL"); //Get query text here to test it in Database Manager //System.Diagnostics.Debug.WriteLine(cmd_txt_filled); //Uncomment this to apply modified query template //oledb_e.Command.CommandText = cmd_txt; //Uncomment this to simply run the prepared update command //oledb_e.Command.CommandText = cmd_txt_filled; } public string ReplaceFirst(string text, string search, string replace) { int pos = text.IndexOf(search); if (pos < 0) { return text; } return text.Substring(0, pos) + replace + text.Substring(pos + search.Length); } private static string DateToParadoxDays(string date) { return (Convert.ToDateTime(date) - Convert.ToDateTime("30.12.1899")).TotalDays.ToString(); }