當Entity Framework 遇上 Oracle
今年換工作,也從原本熟悉的MSSQL轉換到Oracle陣營。
雖然曾與Oracle小小的接觸過,但也僅僅知道參數是從【@】變成【:】的程度。
雖然,新的開發環境套用Entity Framework 5。
但,偶而還是會需要自行下Query Command。
就這麼遇到一個問題。
在Entity Framework情況下我有這麼一段:
var r = db.Database.SqlQuery<string>
("Select t0.PID from WEB_CONFIG t0 Where t0.PID = :p0 and t0.PANME = :p0",
new OracleParameter("p0", "1")).ToList();
要注意一件事情:ODP.NET OracleParameter預設是用Positon來做綁定。
簡單來說,就是靠參數的位置,而不是靠參數名稱來綁定數據的。
在Entity Framework 官網中:https://msdn.microsoft.com/zh-tw/library/system.data.entity.database.sqlquery%28v=vs.113%29.aspx
卻遍尋不著,改變這方法的途徑。
所以,如果真的想執行透過Paramter綁定數據,可以改為以下執行方式:
using(OracleCommand cmd = con.CreateCommand()) {
...
cmd.BindByName = true;
...
}
但,這些都是我原本的問題引起的。
偶而,我們會有一些變數的值都是一樣的,在MSSQL的教育下,宣告成同一個Paramter是很正常的。就像最一開始那段Query。
今天,很自然的一樣這樣做,但,執行時卻會遇到ORA-1008的錯誤訊息。
出錯情境大致如下:
var sql = "Select t0.PID from WEB_CONFIG t0 Where t0.PID = :p0 and t0.Type = :p1 and t0.PANME = :p0";
var r = db.Database.SqlQuery<string>(sql, new OracleParameter("p0", "1"),new OracleParameter("p1", "2")).ToList();
注意一點:我們在兩個:p0中,多了一個:p1。
但,OracelPrameter還是只宣告p0 & p1。
此時就會報錯了!!
解決方法其實,轉換成【ODP.NET OracleParameter預設是用Positon來做綁定】,這樣的想法,大概就會解了。
我的說法就是一個蘿蔔一個坑,的去宣告Parameter就對了。
所以,Stackoverflow也有說,雖然很蠢,但是,將程式碼改成:
var sql = "Select t0.PID from WEB_CONFIG t0 Where t0.PID = :p0 and t0.Type = :p1 and t0.PANME = :p0";
var r = db.Database.SqlQuery<string>(sql, new OracleParameter("p0", "1"),new OracleParameter("p1", "2"),new OracleParameter("p0", "2")).ToList();
這樣下去執行就對了。
雖然問題看似解決了,但其實我的觀念還沒真正清楚,看有無熱心人士可以為我解決了,或是自行找到再回來補充。
若我把程式改成:
var sql = "Select t0.PID from WEB_CONFIG t0 Where t0.Type = :p1 and t0.PID = :p0 and t0.PANME = :p0";
var r = db.Database.SqlQuery<string>(sql, new OracleParameter("p1", "2"),new OracleParameter("p0", "1")).ToList();
將順序改變一下,同時將一樣的p0都放在最後,OracleParamter p0也放在最後。
如此,程式碼還是正確執行。
這個道理何在?我至目前還是無解,期望可以找到正解。
結論,若要透過Entity Framework,目前最好採用一個蘿蔔一個坑方式。
否則,透過OracleCommand,同時將BindbyName設為true,也是不錯的方式。