如何让"选择*"在表格修改后相应地工作?

时间:2017-01-23 10:15:56

标签: c# oracle odp.net

我开发了一个基于外部定义创建表的应用程序。如果这些定义发生更改,则应用程序将删除并重新创建受影响的表。在打开连接时必须这样做,因为该任务是一组任务的一部分。但是,如果我使用&#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 - 这个奇怪的行为的原因 - 表的定义已经改变,它应该重新读取表的定义在执行"选择*"。

之前

3 个答案:

答案 0 :(得分:1)

尝试在连接字符串中设置Metadata Pooling = false,Self Tuning = False和Statement Cache Size = 0.

https://docs.oracle.com/database/122/ODPNT/featConnecting.htm#GUID-0CFEB161-68EF-4BC2-8943-3BDFFB878602

答案 1 :(得分:0)

看起来这是某种缓存问题,无论是ODP.net还是Oracle DBMS本身。但是,如果第二个语句与第一个语句略有不同,则可以避免缓存。上面的代码可以通过将别名分配给表的方式进行修改,该方式不会影响结果,但会使DBMS认为它会收到“新”语句:

...
PerformSelectStar(selectCmd + " alias1", conn);
...
PerformSelectStar(selectCmd + " alias2", conn);
...

当然,这只是一种解决方法。 真正的解决方案是告诉DBMS不需要缓存。

答案 2 :(得分:-1)

尝试修改事务中的表。在您选择之前提交。