2012-04-17 34 views
1

1-使用Oracle.DataAccess错误选择栏最近与ALTER TABLE插入ODP.NET

2-执行一个命令将列添加到表连接到的Oracle XE:改变表TABLE添加塔B INT ;

3-执行命令以选择此列

4-使用DataReader读取。应用程序引发IndexOutOfRangeException:无法找到结果指定列设置

5重新启动应用程序,查询可以正常运行

DataReader的,为什么不能访问我创建刚才列?

这里是一个大而简单的代码来测试:

private void button1_Click(object sender, EventArgs e) 
{ 
    using (OracleConnection con = new OracleConnection(Settings.Default.CS)) 
    { 
     con.Open(); 
     try 
     { 
      using (OracleCommand com = new OracleCommand()) 
      { 
       com.Connection = con; 

       // Create a test table 
       com.CommandText = "CREATE TABLE Test (a int)"; 
       com.ExecuteNonQuery(); 

       // Add one column 
       com.CommandText = "ALTER TABLE Test ADD b int"; 
       com.ExecuteNonQuery(); 

       com.CommandText = "SELECT * FROM Test"; 
       using (DbDataReader dr = com.ExecuteReader()) 
       { 
        MessageBox.Show(dr.FieldCount.ToString()); 
        // Here is showing "2", thats ok 
       } 
      } 
     } 
     finally 
     { 
      con.Close(); 
     } 
    } 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
    using (OracleConnection con = new OracleConnection(Settings.Default.CS)) 
    { 
     con.Open(); 
     try 
     { 
      using (OracleCommand com = new OracleCommand()) 
      { 
       OracleTransaction trans = con.BeginTransaction(); 
       try 
       { 
        // Add a column to table already created 
        com.Connection = con; 
        com.CommandText = "ALTER TABLE Test ADD c int"; 
        com.ExecuteNonQuery(); 

        // Insert a value, ok 
        com.CommandText = "INSERT INTO TEST (a, b, c) VALUES (1, 2, 3)"; 
        com.ExecuteNonQuery(); 

        trans.Commit(); 
       } 
       catch 
       { 
        trans.Rollback(); 
        throw; 
       } 

       // Selecting only "c" column 
       com.CommandText = "SELECT c FROM Test"; 
       using (DbDataReader dr = com.ExecuteReader()) 
       { 
        if (dr.Read()) 
         MessageBox.Show(Convert.ToInt32(dr["c"]).ToString()); 
         // Showing correct value, ok 
       } 

       // Uncomment these lines to solve problem 
       //con.Close(); 
       //OracleConnection.ClearAllPools(); 
       //con.Open(); 

       // Selecting all fields * from table 
       com.CommandText = "SELECT * FROM Test"; 
       using (DbDataReader dr = com.ExecuteReader()) 
       { 
        MessageBox.Show(dr.GetSchemaTable().Rows.Count.ToString() + "/" + dr.FieldCount.ToString()); 
        // HERE IS THE PROBLEM: message are showing 2/2, but table haves 3 fields 

        if (dr.Read()) 
         MessageBox.Show(Convert.ToInt32(dr["c"]).ToString()); 
        // Here throws IndexOutOfRangeException: Unable to find specified column in result set 
       } 
      } 
     } 
     finally 
     { 
      con.Close(); 
     } 
    } 
} 
+0

对我来说,这听起来像某种元数据缓存。也许 'OracleConnection.PurgeStatementCache()'方法可以帮助吗? – 2012-04-17 21:15:46

+0

我在添加列之后尝试了PurgeStatementCache,然后再选择,但没有奏效。 – rkawano 2012-04-18 12:36:37

+0

'OracleTransaction'应该被丢弃,所以应该有它自己的'using'块。您可以选择使用['OracleCommand.CreateCommand'](http://docs.oracle.com/html/B28089_01/OracleConnectionClass.htm#i1001011),因为这样可以节省您需要自行将连接分配给命令。 – WhiteKnight 2012-04-18 20:26:00

回答

1

这听起来像插入事务,当你执行读者尚未提交。我想,你可以通过关闭您插入,然后再次打开它,你执行了读者之前刚刚经过的连接进行验证(您可能需要使用OracleConnection.ClearAllPools)

+0

在我们的真实应用程序中,我们使用的是交易,行为完全相同。重新打开连接不能解决,但重新启动应用程序解决。 – rkawano 2012-04-17 20:52:20

+0

这包括调用OracleConnection.ClearAllPools吗?如果你们正在使用连接池,那么即使你调用“close”,框架也会将连接对象保留在池中。 – Ulises 2012-04-17 21:05:34

+0

ClearAllPools工作正常!我执行命令添加列,关闭连接,执行clearAllPools并重新打开连接。工作得很好,我不需要重新启动所有的应用程序。谢谢! – rkawano 2012-04-18 12:52:51

0

尝试使用OracleConnection.BeginTransaction创建一个事务,然后Commit在选择之前,如文档中的example所示。

+0

我尝试在添加列之前开始事务,并在插入值之后进行提交,但没有奏效。 – rkawano 2012-04-18 13:10:31

+0

您能否编辑您的示例以显示您对交易的使用? – WhiteKnight 2012-04-18 13:15:59

+0

编辑button2_Click – rkawano 2012-04-18 13:29:07