1

请帮助解决我的问题。尝试从我用 C# 编写的应用程序更新 MS Access(2000 格式)数据库 (.mdb) 中新添加的表记录时,出现错误“并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条”。这个错误相当普遍,我尝试了不同论坛上建议的解决方案,但没有成功。

这是我一步一步做的:

我在 mdb 中有一个表“TRACKS”,其中包含以下列:

  • ID - 类型“自动编号”(键列)
  • 标题 - '文本'
  • 全文 - '文本'
  • 长度 - '日期/时间'

    1. 我以这种方式建立与数据库的连接并获取表记录:

      public partial class MainForm : Form
      {
          public OleDbConnection dbConn = new OleDbConnection();
          public DataSet dataset = new DataSet();
      
          protected OleDbDataAdapter adTracks = new OleDbDataAdapter();
      
          protected OleDbCommandBuilder cmb;
      
          ArrayList arrArtists = new ArrayList();
      
          public MainForm(string strFileName)
          {
              InitializeComponent();
              cmb = new OleDbCommandBuilder(adTracks);
          }
      
          private void OnLoad(object sender, EventArgs e)
          {
              dbConn.ConnectionString = Properties.Settings.Default.dbConnectionString;
              OleDbCommand cmTracks = new OleDbCommand("Select * from Tracks", dbConn);
      
              OleDbDataAdapter adapter = new OleDbDataAdapter();
      
              try
              {
                  dbConn.Open();
                  adTracks.SelectCommand = cmTracks;
                  adTracks.Fill(dataset, "Tracks");
              }
              catch (Exception err)
              {
                  MessageBox.Show(err.Message);
                  return;
              }
              finally
              {
                  dbConn.Close();
              }
      
              cboOriginal.DataSource = dataset.Tables["Tracks"];
              cboOriginal.DisplayMember = "FullTitle";
              cboOriginal.ValueMember = "ID";
              cboOriginal.SelectedIndex = -1;
      
              adTracks.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
          }
      }
      
    2. 然后我使用此代码向表中添加一条新记录(txtTitle并且txtGenTitle控件包含记录的值):

      DataTable dt;
      DataRow dr;
      int newID;
      
      dt = dataset.Tables["Tracks"];
      dr = dt.NewRow();
      dr["Title"] = txtTitle.Text;
      dr["FullTitle"] = txtGenTitle.Text;
      
      dt.Rows.Add(dr);
      
      try
      {
          dbConn.Open();
          adTracks.Update(dt);
      }
      catch (Exception err)
      {
          MessageBox.Show("Error adding new track '" + txtGenTitle.Text + "':\n" + err.Message);
          return;
      }
      finally
      {
          dbConn.Close();
      }
      
      res = dt.Select("FullTitle = '" + txtGenTitle.Text.Replace("'", "''") + "'");
      if (res.Length != 0)
      {
          newID = (int)res[0]["ID"];
      
          // continue with newID
      }
      

      此代码成功执行:新记录添加到表中,本地 DataTable 和 mdb 文件中的实际表。在此处理程序中接收到键列的新自动递增值:

      protected void OnRowUpdated(object sender, OleDbRowUpdatedEventArgs args)
      {
          if (args.StatementType == StatementType.Insert)
          {
              OleDbCommand idCMD = new OleDbCommand("SELECT @@IDENTITY", dbConn);
              args.Row["ID"] = (int)(idCMD.ExecuteScalar());
          }
      }
      

      具有此 ID 的行现在有RowState == Unchanged,所以一切似乎都正常。

    3. 现在我想更新这个新添加的记录中的一些值(来自txtLength控制):

      DataTable dt;
      DataRow dr;
      DataRow[] res;
      
      dt = dataset.Tables["Tracks"];
      res = dt.Select("FullTitle = '" + txtGenTitle.Text.Replace("'", "''") + "'");
      
      if (res.Length != 0)
      {
          TimeSpan tsNew = TimeSpan.Zero, tsOld = TimeSpan.Zero;
          if (txtLength.Text != String.Empty) tsNew = TimeSpan.Parse(txtLength.Text);
          if (!(res[0]["Length"] is DBNull))
          {
              DateTime date = (DateTime)res[0]["Length"];
              tsOld = date.TimeOfDay;
          }
      
          if (tsNew != TimeSpan.Zero && (tsOld == TimeSpan.Zero || tsOld.CompareTo(tsNew) < 0))
          {
              if (tsNew != TimeSpan.Zero && (tsOld == TimeSpan.Zero || tsOld.CompareTo(tsNew) < 0)) res[0]["Length"] = txtLength.Text;
      
              if (String.Compare((string)res[0]["Title"], txtTitle.Text, true) != 0)
              {
                  res[0]["Title"] = txtTitle.Text;
                  res[0]["FullTitle"] = txtGenTitle.Text;
              }
      
              try
              {
                  dbConn.Open();
                  adTracks.Update(dt);
              }
              catch (Exception err)
              {
                  MessageBox.Show("Error updating track '" + txtGenTitle.Text + "':\n" + err.Message);
                  return;
              }
              finally
              {
                  dbConn.Close();
              }
          }
      }
      

      adTracks.Update(dt) 并在“并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条”这一行得到一个错误。数据库没有更新,DataTable 也没有。

这可能意味着记录 ID 存在一些错误 - 插入后它没有更新为正确的值。但这里的情况并非如此:OnRowUpdated在第 2 步的处理程序中使用正确的 ID 更新 ID,并将具有此 ID 的记录添加到表 mdb 文件中。在调用前的第 3 步中adTracks.Updateres[0]还包含正确的 ID 值和RowState == Modified。但我仍然得到这个错误。我究竟做错了什么?

按照此处的建议添加dt.AcceptChanges()之后- 无济于事。adTracks.Update(dt)


更新:

1. krish建议的尝试方法:

try/catch我在步骤 3 的块之前添加了以下行:

string cmd = "UPDATE TRACKS SET Length = '" + res[0]["Length"] + "' WHERE ID = " + res[0]["ID"];
adTracks.UpdateCommand = new OleDbCommand(cmd, dbConn);

它有效!数据库已更新并相应DataRow获取RowState == Unchanged。这是一个很好的解决方法。但我仍然想知道为什么“传统”方法在这里不起作用。当需要更新许多列时,解决方法不是很方便。此外,它似乎只在我更新单行时是可以接受的,并且我需要一次更新多行的能力。

2. hynsey建议的尝试方法:

我用adTracks.Update(dt);以下代码替换了第 3 步中的行:

using (OleDbDataAdapter da = new OleDbDataAdapter ("Select * from Tracks", dbConn))
{
    OleDbCommandBuilder cb = new OleDbCommandBuilder(da);
    da.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
    da.Update(dt);
}

可悲的是,行为根本没有改变——同样的错误“并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条”。

这是我在所有 3 个步骤中使用的代码(与原始代码比较):

1. 
        public partial class MainForm : Form
        {
            public OleDbConnection dbConn = new OleDbConnection();
            public DataSet dataset = new DataSet();

            protected OleDbDataAdapter adTracks = new OleDbDataAdapter();

            ArrayList arrArtists = new ArrayList();

            public MainForm(string strFileName)
            {
                InitializeComponent();
            }

            private void OnLoad(object sender, EventArgs e)
            {
                dbConn.ConnectionString = Properties.Settings.Default.dbConnectionString;

                try
                {
                    dbConn.Open();
                    adTracks = new OleDbDataAdapter("Select * from Tracks", dbConn));
                    adTracks.Fill(dataset,"Tracks");    
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message);
                    return;
                }
                finally
                {
                    dbConn.Close();
                }

                cboOriginal.DataSource = dataset.Tables["Tracks"];
                cboOriginal.DisplayMember = "FullTitle";
                cboOriginal.ValueMember = "ID";
                cboOriginal.SelectedIndex = -1;

                adTracks.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
            }
        }

2.
        DataTable dt;
        DataRow dr;
        int newID;

        dt = dataset.Tables["Tracks"];
        dr = dt.NewRow();
        dr["Title"] = txtTitle.Text;
        dr["FullTitle"] = txtGenTitle.Text;

        dt.Rows.Add(dr);

        try
        {
            dbConn.Open();
            using (OleDbDataAdapter da = new OleDbDataAdapter ("Select * from Tracks", dbConn)) 
            {
                OleDbCommandBuilder cb = new OleDbCommandBuilder(da); 
                da.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
                da.Update(dataset, "Tracks"); 
            }
        }
        catch (Exception err)
        {
            MessageBox.Show("Error adding new track '" + txtGenTitle.Text + "':\n" + err.Message);
            return;
        }
        finally
        {
            dbConn.Close();
        }

        res = dt.Select("FullTitle = '" + txtGenTitle.Text.Replace("'", "''") + "'");
        if (res.Length != 0)
        {
            newID = (int)res[0]["ID"];

            // continue with newID
        }        

3.
        DataTable dt;
        DataRow dr;
        DataRow[] res;

        dt = dataset.Tables["Tracks"];
        res = dt.Select("FullTitle = '" + txtGenTitle.Text.Replace("'", "''") + "'");

        if (res.Length != 0)
        {
            TimeSpan tsNew = TimeSpan.Zero, tsOld = TimeSpan.Zero;
            if (txtLength.Text != String.Empty) tsNew = TimeSpan.Parse(txtLength.Text);
            if (!(res[0]["Length"] is DBNull))
            {
                DateTime date = (DateTime)res[0]["Length"];
                tsOld = date.TimeOfDay;
            }

            if (tsNew != TimeSpan.Zero && (tsOld == TimeSpan.Zero || tsOld.CompareTo(tsNew) < 0))
            {
                if (tsNew != TimeSpan.Zero && (tsOld == TimeSpan.Zero || tsOld.CompareTo(tsNew) < 0)) res[0]["Length"] = txtLength.Text;

                if (String.Compare((string)res[0]["Title"], txtTitle.Text, true) != 0)
                {
                    res[0]["Title"] = txtTitle.Text;
                    res[0]["FullTitle"] = txtGenTitle.Text;
                }

                try
                {
                    dbConn.Open();
                    using (OleDbDataAdapter da = new OleDbDataAdapter ("Select * from Tracks", dbConn)) 
                    {
                        OleDbCommandBuildercb = new OleDbCommandBuilder(da); 
                        da.Update(dataset , "Tracks"); 
                    }
                }
                catch (Exception err)
                {
                    MessageBox.Show("Error updating track '" + txtGenTitle.Text + "':\n" + err.Message);
                    return;
                }
                finally
                {
                    dbConn.Close();
                }
            }
        }

3. 为了调查为什么我的初始代码不起作用,我提供了有关错误的更多详细信息:

OnRowUpdated尽管出现错误,还是调用了处理程序,并且我能够检查args传递给处理程序的参数。args.Row具有RowState == Modified并且args.Command具有以下内容CommandText(为了便于阅读,我添加了换行符):

UPDATE Tracks SET Length = ? WHERE ((ID = ?) AND
((? = 1 AND Title IS NULL) OR (Title = ?)) AND
((? = 1 AND FullTitle IS NULL) OR (FullTitle = ?)) AND
((? = 1 AND GenreID IS NULL) OR (GenreID = ?)) AND
((? = 1 AND StyleID IS NULL) OR (StyleID = ?)) AND
((? = 1 AND SubStyleID IS NULL) OR (SubStyleID = ?)) AND
((? = 1 AND Length IS NULL) OR (Length = ?)) AND
((? = 1 AND UseOriginal IS NULL) OR (UseOriginal = ?))
AND ((? = 1 AND Version IS NULL) OR (Version = ?)) AND
((? = 1 AND TrackID IS NULL) OR (TrackID = ?)) AND
((? = 1 AND SpecPresConjunctor IS NULL) OR (SpecPresConjunctor = ?)) AND
((? = 1 AND SpecFeatConjunctor IS NULL) OR (SpecFeatConjunctor = ?)) AND
((? = 1 AND FreeRecord IS NULL) OR (FreeRecord = ?)))

谁能告诉这个生成的命令有什么问题?“GenreID”、“StyleID”等是“TRACKS”表中的其他列。我不知道所有这些“?” 意思是。

此外,当异常发生时,堆栈上的最新调用如下:

at System.Data.Common.DbDataAdapter.UpdatedRowStatusErrors(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
at System.Data.Common.DbDataAdapter.UpdatedRowStatus(RowUpdatedEventArgs rowUpdatedEvent, BatchCommandInfo[] batchCommands, Int32 commandCount)
at System.Data.Common.DbDataAdapter.Update(DataRow[] dataRows, DataTableMapping tableMapping)
at System.Data.Common.DbDataAdapter.UpdateFromDataTable(DataTable dataTable, DataTableMapping tableMapping)
at System.Data.Common.DbDataAdapter.Update(DataTable dataTable)
at *my code as above*
4

2 回答 2

0

用这个替换你的OnLoad方法:

    private void OnLoad(object sender, EventArgs e)
    {
        dbConn.ConnectionString = Properties.Settings.Default.dbConnectionString;

    try
    {
        dbConn.Open();
        adTracks = new OleDbDataAdapter("Select * from Tracks", dbConn));
        adTracks.Fill(dataset,"Tracks");    
    }
    catch (Exception err)
    {
        MessageBox.Show(err.Message);
        return;
    }
    finally
    {
        dbConn.Close();
    }

    cboOriginal.DataSource = dataset.Tables["Tracks"];
    cboOriginal.DisplayMember = "FullTitle";
    cboOriginal.ValueMember = "ID";
    cboOriginal.SelectedIndex = -1;

    adTracks.RowUpdated += new OleDbRowUpdatedEventHandler(OnRowUpdated);
}

然后是更新数据集的代码:( 注意,我更正了上面评论中存在的错误引用。)adTracks

using (OleDbDataAdapter da = new OleDbDataAdapter ("Select * from Tracks", dbConn)) 
{
OracleCommandBuilder cb = new OracleCommandBuilder(da); 
da.Update(dataset , "Tracks"); 
}
于 2015-06-15T11:17:52.903 回答
0

并发有同样的问题。没有任何效果。2 天后,我看到了这篇关于 Ms Access 和数据类型小数的文章。本文指出应避免使用此数据类型。

所以我使用数据类型 Double 重新设计了表格。用新名称保存它。复制数据,最后用旧名称重命名新表。

在 Visual Studio 中,我删除了 Dataset.xsd 并添加了一个新的 Dataset

终于成功了。

请阅读: https ://www.fmsinc.com/microsoftaccess/database-design/decimal_data_type/index.htm

于 2021-05-27T12:19:09.247 回答