2017-01-23 20 views
0

我開發了一個基於外部定義創建表的應用程序。如果這些定義發生更改,則應用程序將刪除並重新創建受影響的表。在連接打開時必須這樣做,因爲該任務是一組任務的一部分。但是,如果我查詢一個隨後用「select *」更改的表,我會得到舊定義的列。如果列已添加到表中,「select *」不會看到它。下面是一個說明這是一個示例代碼:使用如何讓表「select *」在表被修改後相應地工作?

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); 
    } 
} 

軟件版本:4.5.1 .NET和Oracle 12.1

如果重置連接部分被激活,「SELECT *」的作品,但隨後臨時表中的所有數據都會刷新,這是不希望的。

我想知道是否有某種方法告訴ODP.net或Oracle--無論哪種原因導致這種奇怪的行爲 - 表的定義已被更改,並且它應該在執行前重新讀取表定義「選擇 *」。

+0

爲什麼要這樣做?看起來像它違背了關係數據庫系統中的觀點,您應該查看DocumentDB解決方案......如果您確實需要這樣做,請使用數據庫提供的元數據視圖來獲取列的明確列表並將其用於查詢而不是* – Milney

+0

@Milney這些表中的數據與標準化數據庫上的SQL查詢結合使用。雖然把它放在其他地方是可能的,但它也會導致查詢變得更加複雜(即代碼將更難以閱讀和維護)。 –

+1

問題可以解決:訣竅是以不影響結果的方式稍微修改語句,如下所示:http://stackoverflow.com/a/16861388/3424360 –

回答

-1

嘗試修改事務中的表。在選擇之前提交。

+0

在Oracle中,CREATE TABLE和ALTER TABLE不知道事務,即它們立即發生。但是,我試圖將這些陳述包含在交易中,但行爲是相同的。 –

0

看起來這是某種緩存問題,無論是ODP.net還是Oracle DBMS本身。但是,如果第二條語句與第一條語句略有不同,則可以規避高速緩存。上面的代碼可以在別名被分配到不影響結果表的方式進行修改,但使得DBMS認爲它會得到一個「新」的聲明:

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

當然,這只是一個解決方法。 A 真正的解決方案將告訴DBMS不需要緩存。

+0

在上面的問題中查看我的評論,獲取關於如何關閉元數據池和語句緩存的建議。 –

+0

@ChristianShay您在上述註釋中的提示指向正確的方向:添加「Metadata Pooling = false; Self Tuning = false;」到連接字符串解決了這個問題。但是,我必須查明是否有任何不需要的副作用,特別是關於查詢性能。 –