当使用 TransactionLevel.ReadUncommissed 从准备好的语句中从 C# 将行插入 MS Access 时,顺序似乎不正确

发布于 2024-07-12 11:18:25 字数 2835 浏览 3 评论 0原文

我有一些 C# 代码,它使用准备好的语句将信息(逐行)写入访问数据库。 我正在使用 OleDb 和 TransactionLevel.ReadUncommited,因为有时我需要在提交数据之前查看数据。

问题似乎是,在 7 个不同表中的 1 个上,我从数据库检索记录的顺序与我放入它们的顺序不同。 我尝试使用它时大约每 4 次就会发生一次这种情况,所以我似乎无法真正调试它。

编辑 这里排序很重要的原因是我们将表转储到 Excel 工作表中,该工作表与那里已有的数据相匹配。 排序依据可能会取得一些进展,但有一列按运动(即 N-NW)排序,无法排序以与工作表上的数据匹配。

我倾向于它是准备好的语句的插入命令的竞争条件(即,有太多的访问需要一次处理,因此它们会变得混乱)。

有人对此有什么想法吗? 以下是我正在做的一些片段: (抱歉,长度太长了,我尝试尽可能多地剪掉,但仍然把主要部件剪掉了)

protected override void PopulateTmpTable()
  {
    OleDbCommand objComm = null;
    try
    {
      objComm = new OleDbCommand("", mDbconn);
      ...
      //Begin SQL Transaction
      mTr = mDbconn.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
      objComm.Transaction = mTr;
      //Start Populating Temp Table
      for (int i = 1; i <= mNrows; i++)
      {
        ...
        ProcessNode(objComm, node, approaches);
        ProcessNodeSummary(objComm, node);
      }
      ProcessSummary(objComm);
    }
    catch (Exception e) { }
    finally
    {
      if (mTr != null) mTr.Commit();
      if (objComm != null) objComm.Dispose();
    }
  }  //End Method PopulateTmpTable

  private void ProcessNode(OleDbCommand objComm, string node, List<string> approaches)
  {
    try
    {
      ...
      OleDbCommand objComm2 = new OleDbCommand("", mDbconn, mTr);
      for (int k = 0; k < MaxLegs; k++)
      {
        ...
            total = ProcessIterations(objComm, node, turning[m], m);
          }
          objComm.ExecuteNonQuery();
        }  //End if
      }  //End for
    }
    catch { }
  }  //End Method ProcessNode

private List<double> ProcessIterations(OleDbCommand objComm, string node, string turn, int m)
  {
    try
    {
      OleDbCommand objComm2 = new OleDbCommand("", mDbconn, mTr);
      OleDbDataReader objRead;
      objComm.Parameters["parameter"].Value = //Stuff (x2)
        for (int j = 0; j < mIterations; j++)
        {
          ...
          objComm2.CommandText = "SELECT ROUND(AVG(Delay),1), COUNT(VehNo) FROM [TABLE] WHERE NodeNo=" + node + " AND Movement='" + turn + "' AND Iteration=" + mIterationValue[j] + mFilter[1];
          objRead = objComm2.ExecuteReader();
          objRead.Read();
          try
          {
              objComm.Parameters["more parameters"].Value = objRead[0];
              ...
          }
          catch { }
          objRead.Close();
        }//End for
        ...
        objComm.ExecuteNonQuery();
        objComm2.CommandText = "UPDATE " + mTmptable + " SET ave=" + avg + ",minimum=" + mMini[m] + ",maximum=" + mMaxi[m] + ",dev=" + stDev + " WHERE node='" + node + "' AND movement = '" + temp + "';";
        objComm2.ExecuteNonQuery();
      }
    }
    catch{}
    return mTotal;
  }  //End Function ProcessIterations

I have some code in c# that is writing information (row by row) into an access database using prepared statements. I am using OleDb, and a TransactionLevel.ReadUncommitted because sometimes I need to look at the data before committing it.

The problem seems to be that on 1 out of 7 different tables, the ordering that I retrieve the records from the database isn't the same ordering I put them in as. This happens about 1 out of every 4 times I try to use it, so I can't really seem to debug it.

Edit
The reason ordering is important here is that we are dumping the table to an excel sheet which matches up with data already existing on there. Order by might make some progress, but there is a column which is ordered by a movement (i.e. N-NW) that couldn't be ordered to match up with the data on the sheet.

I'm leaning toward it being a race condition of the prepared statement's insert command (i.e. there are too many for access to handle at once, so they get jumbled).

Does anybody have any thoughts on this? Below are a couple of snippets of what I'm doing:
(Sorry about the length, I tried to cut out as much as I could but still get the main components out)

protected override void PopulateTmpTable()
  {
    OleDbCommand objComm = null;
    try
    {
      objComm = new OleDbCommand("", mDbconn);
      ...
      //Begin SQL Transaction
      mTr = mDbconn.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
      objComm.Transaction = mTr;
      //Start Populating Temp Table
      for (int i = 1; i <= mNrows; i++)
      {
        ...
        ProcessNode(objComm, node, approaches);
        ProcessNodeSummary(objComm, node);
      }
      ProcessSummary(objComm);
    }
    catch (Exception e) { }
    finally
    {
      if (mTr != null) mTr.Commit();
      if (objComm != null) objComm.Dispose();
    }
  }  //End Method PopulateTmpTable

  private void ProcessNode(OleDbCommand objComm, string node, List<string> approaches)
  {
    try
    {
      ...
      OleDbCommand objComm2 = new OleDbCommand("", mDbconn, mTr);
      for (int k = 0; k < MaxLegs; k++)
      {
        ...
            total = ProcessIterations(objComm, node, turning[m], m);
          }
          objComm.ExecuteNonQuery();
        }  //End if
      }  //End for
    }
    catch { }
  }  //End Method ProcessNode

private List<double> ProcessIterations(OleDbCommand objComm, string node, string turn, int m)
  {
    try
    {
      OleDbCommand objComm2 = new OleDbCommand("", mDbconn, mTr);
      OleDbDataReader objRead;
      objComm.Parameters["parameter"].Value = //Stuff (x2)
        for (int j = 0; j < mIterations; j++)
        {
          ...
          objComm2.CommandText = "SELECT ROUND(AVG(Delay),1), COUNT(VehNo) FROM [TABLE] WHERE NodeNo=" + node + " AND Movement='" + turn + "' AND Iteration=" + mIterationValue[j] + mFilter[1];
          objRead = objComm2.ExecuteReader();
          objRead.Read();
          try
          {
              objComm.Parameters["more parameters"].Value = objRead[0];
              ...
          }
          catch { }
          objRead.Close();
        }//End for
        ...
        objComm.ExecuteNonQuery();
        objComm2.CommandText = "UPDATE " + mTmptable + " SET ave=" + avg + ",minimum=" + mMini[m] + ",maximum=" + mMaxi[m] + ",dev=" + stDev + " WHERE node='" + node + "' AND movement = '" + temp + "';";
        objComm2.ExecuteNonQuery();
      }
    }
    catch{}
    return mTotal;
  }  //End Function ProcessIterations

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北斗星光 2024-07-19 11:18:25

在 Jet 中,表的聚集索引(物理顺序)由 PRIMARY KEY 确定,或者在没有 PK 的情况下由引擎选择(随机?)的另一个键。 但是,仅当压缩数据库文件(.mdb、.mde、.accdb)时才会发生物理排序。 压缩之后(或第一次压缩之前)插入的行按日期/时间顺序插入。 现在,Jet 的 DATETIME 数据类型支持的最小时间粒度是一秒,尽管在幕后该值存储为双精度浮点数,因此我想知道粒度是否不足以满足您的目的。 但为什么要依赖一个老旧引擎的如此缺乏记录的功能......?

如果您知道插入行的顺序,则在数据库中对此进行建模,例如使用 INTEGER 列来存储您的应用程序负责为其提供值的序列号。 为了确定起见,也在该列上放置一个 UNIQUE 约束。 然后只需按查询中的序列列进行 ORDER BY 即可。

In Jet, the clustered index (physical ordering) of a table is determined by the PRIMARY KEY or, in absence of a PK, another key chosen (randomly?) by the engine. However, physical ordering only occurs when the database file (.mdb, .mde, .accdb) is compacted. Rows inserted subsequent to compacting (or before the first compact) are inserted in date/time order. Now, the smallest time granule supported by Jet's DATETIME data type is one second, though under the covers the value is stored as a double float, therefore I'm wondering whether the granularity is not fine enough for your purposes. But why rely on such poorly documented features of an elderly engine...?

If you know ther order in which you insert the rows then model this in the database e.g. use an INTEGER column to store a sequence number for which your app is in charge of supplying the values. And put a UNIQUE constraint on the column too, just to be sure. Then simply ORDER BY your sequence column in queries.

唯憾梦倾城 2024-07-19 11:18:25

在 PopulateTmpTable() 方法中,即使发生错误,您也会提交事务。 这就是你的意图吗?

在 ProcessNode() 中,您传入一个命令对象,创建一个新对象,然后使用传入的命令对象?

In your PopulateTmpTable() method, you are commiting the transaction even if an error occured. Is that what you intended?

In ProcessNode() you pass in a command object, create a new one and then use the one passed in?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文