我开发了一个基于外部定义创建表的应用程序。如果这些定义发生更改,则应用程序将删除并重新创建受影响的表。在打开连接时必须这样做,因为该任务是一组任务的一部分。但是,如果我使用&#34查询已更改的表;请选择*"之后,我得到了旧定义的列。如果已将列添加到表中,"选择*"没有看到它。以下示例代码演示了这一点:
private static void OraSelectStarProblem()
{
var tabDef1 = "CREATE TABLE TEMP_PS_000 (SESSIONID RAW(16), EXECNR NUMBER, DUEDATE DATE)";
//var tabDef2 = "CREATE TABLE TEMP_PS_000 (YASESSIONID RAW(16), YAEXECNR NUMBER, YADUEDATE DATE, NEWFIELD VARCHAR2(100))";
var tabDef2 = "CREATE TABLE TEMP_PS_000 (YADUEDATE DATE, NEWFIELD VARCHAR2(100), SOMEOTHER integer)"; // causes ORA-00932 when querying
var selectCmd = "select * from TEMP_PS_000";
using (var conn = new OracleConnection(GetConnStr()))
{
conn.Open();
//PerformSelectStar(selectCmd, conn);
DropTempTable(conn);
Console.Write("Creating TEMP_PS_000 with 3 columns... ");
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = tabDef1;
cmd.ExecuteNonQuery();
}
Console.WriteLine("Done!");
PerformSelectStar(selectCmd, conn);
//conn.PurgeStatementCache(); // no effect
//conn.FlushCache(); // no effect
/*Console.WriteLine("Resetting connection");
conn.Close();
OracleConnection.ClearPool (conn);
conn.Open();*/
DropTempTable(conn);
//conn.PurgeStatementCache(); // no effect
//conn.FlushCache(); // no effect
Console.Write("Creating TEMP_PS_000 with 4 columns... ");
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = tabDef2;
cmd.ExecuteNonQuery();
}
Console.WriteLine("Done!");
PerformSelectStar(selectCmd, conn);
}
}
private static void DropTempTable(OracleConnection conn)
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "begin drop_table('TEMP_PS_000'); end;";
cmd.ExecuteNonQuery();
}
}
private static void PerformSelectStar(string selectCmd, OracleConnection conn)
{
try
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = selectCmd;
var dataAdapter = new OracleDataAdapter(cmd);
var dataSet = new DataSet();
dataAdapter.Fill(dataSet);
var columns = "";
foreach (DataColumn column in dataSet.Tables[0].Columns)
{
columns += column.ColumnName + " ";
}
Console.WriteLine("Columns: " + columns);
}
}
catch (Exception ex)
{
Console.WriteLine("PerformSelectStar: " + ex.Message);
}
}
使用的软件版本:.net 4.5.1和Oracle 12.1
如果激活了重置连接的部分,"选择*"工作,但然后刷新临时表中的所有数据,这是不希望的。
我想知道是否有某种方法告诉ODP.net或Oracle - 这个奇怪的行为的原因 - 表的定义已经改变,它应该重新读取表的定义在执行"选择*"。
之前答案 0 :(得分:1)
尝试在连接字符串中设置Metadata Pooling = false,Self Tuning = False和Statement Cache Size = 0.
答案 1 :(得分:0)
看起来这是某种缓存问题,无论是ODP.net还是Oracle DBMS本身。但是,如果第二个语句与第一个语句略有不同,则可以避免缓存。上面的代码可以通过将别名分配给表的方式进行修改,该方式不会影响结果,但会使DBMS认为它会收到“新”语句:
...
PerformSelectStar(selectCmd + " alias1", conn);
...
PerformSelectStar(selectCmd + " alias2", conn);
...
当然,这只是一种解决方法。 真正的解决方案是告诉DBMS不需要缓存。
答案 2 :(得分:-1)
尝试修改事务中的表。在您选择之前提交。