Oracle Client版本問題困擾過很多次,之前由網友回饋得知Managed ODP.NET,一直沒深入研究過,直到今天完成評估,新武器一枚入手。

過去我們常用的Oracle.DataAccess(ODP.NET),骨子裡其實是走Unmanaged,得靠oci.dll那堆程式庫才能連上資料庫,因此安裝時必須一併安裝Oracle Client,而Unmanaged Oracle Client有32位元跟64位元之分,許多開發者還因此學會IIS Application Pool啟用32位元模式的技巧呢!加上Oracle.DataAccess.dll執行時需存取Oracle Client檔案,我還因此學會排除NTFS權限問題PATH環境變數等技巧,ODP.NET真的讓我成長好多… orz

由以上的血淚經驗,已足以說明Managed ODP.NET的長處:

  1. 不需要安裝龐大的Oracle Client,只用一個Oracle.ManagedDataAccess.dll就可搞定連線。
  2. 不必再為32位元跟64位元版本問題困擾,Oracle.ManagedDataAccess.dll的目標平台是Any CPU!(灑花)
    註:若程式啟用分散式交易,還需動用另一顆區分32及64版本的Oracle.ManagedDataAccessDTC.dll,但專案不需加入參照,Managed ODP.NET會自動載入正確版本

補充:除了Oracle.ManagedDataAccess.dll,若使用EF6+或Code First,專案需再多參照Oracle.ManagedDataAccess.EntityFramework.dll。

Managed ODP.NET可由Oracle官網下載取得,它被歸類為64-bit ODAC:

注意:Managed ODP.NET支援Entity Framework,但不提供設計階段支援,如果想在Visual Studio使用Entity Framework專案項目,仍須安裝32位元版ODAC with Oracle Developer Tools for Visual Studio,另一方面,開發者通常會用到SQL Plus或第三方Oracle資料庫工具,故開發環境仍會以ODAC 32位元為主,伺服器或大量部署的客戶端才是Managed ODP.NET展現威力的主戰場。

Managed版ODP.NET很小,只有2.53M,ZIP檔解壓縮可得到odp.net、network資料夾,readme.html安裝說明以及install_odpm.bat、uninstall_odpm.bat,為安裝及解除安裝批次檔。

一般會用install_odpm.bat c:\oracle both true安裝及註冊,install_odpm.bat有三個參數,第一個參數為安裝資料夾(將解壓縮內容複製到指定路徑再註冊),第二個參數為x86、x64、both三者擇一,第三個參數則決定是否要將元件加入GAC及在machine.config加入設定,如果要執行Entity Framework,請選true。

安裝動作很單純,下完指令瞬間完成,跟Unmanaged ODP.NET的安裝相比,是高鐵 vs 牛車的差別。

安裝完成後,下一步是換上作業環境專用的資料庫名稱設定檔,在本例中,TNSNAMES.ORA預設放在c:\oracle\network\admin\目錄。

要使用Managed ODP.NET時,專案必須做些修改,將Oracle.DataAccess參照改成Oracle.ManagedDataAccess,但OracleConnection、OracleCommand等用法都相同,程式碼幾乎[註]不需更動。(註:Managed ODP.NET與Unmanaged ODP.NET仍存在些許差異,不過依文件所列項目,我手上的程式應該都不用修改)

使用Visual Studio開發的專案,改用Managed ODP.NET的捷徑是透過NuGet下載:(該程式套件由Oracle官方提供,可安心服用)

前面提到,實務上Visual Studio開發機器多已安裝32位元ODAC(否則無法在專案中設計及修改Entity Framework模型),改由NuGet取得Managed ODP.NET後,取得TNS名稱的方式跟Unmanaged ODP.NET有所不同,傳統ODP.NET主要依賴Registry設定,而Managed ODP.NET則有自己解析TNS名稱的順序:參考

  1. .NET config裡dataSources區塊裡的設定(資料庫別名設定可以直接寫在config裡,如此連TNSNAMES.ORA都不需要)
  2. 由.NET config檔TNS_ADMIN設定所指路徑找到TNSNAMES.ORA
  3. EXE檔所在目錄下的TNSNAMES.ORA
  4. 環境變數%TNS_ADMIN%路徑下的TNSNAME.ORA
  5. 環境變數%ORACLE_HOME%\network\admin路徑下的TNSNAME.ORA

就這樣,只要一個Oracle.ManagedDataAccess.dll,就能連上Oracle,很棒吧?

【結論】

不需要安裝笨重的Oracle Client,不用擔心32位元跟64位元版本打架,.NET程式就能輕鬆連上Oracle資料庫,是Managed ODP.NET最大亮點。在伺服器只運行.NET程式或是要大量部署到客戶端的場合,改用Managed ODP.NET可大幅簡化Oracle Client部署作業,是很不錯的選擇!

【2015-04-01更新】

感謝同事Jean補充目前改用Managed ODP.NET可能欠缺的功能:(但未來應會陸續補上)

  1. XML相關功能
  2. 不支援的OracleDbType:XmlType、Array、Boolean、Object、Ref
  3. OracleAdvanceQueue(罕用)
  4. OracleBulkCopy

Comments

# by Larry

感謝黑大 馬上用馬上見效 不是見笑XD

# by 狐狸俊

請問黑大: 這是 bug 嗎?以下程式會出現 ORA-01008: 部份變數未被連結 。 using (Oracle.ManagedDataAccess.Client.OracleConnection conn = ...) { conn.Open(); Oracle.ManagedDataAccess.Client.OracleCommand command = conn.CreateCommand(); command.CommandText = @"select to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss') as Data from dual where ('aa' = :p1 or :p1 is null) and ('bb' = :p2 or :p2 is null)"; command.Parameters.Add("p1", "aa"); command.Parameters.Add("p2", "bb"); using (Oracle.ManagedDataAccess.Client.OracleDataReader reader = command.ExecuteReader()) { while (reader.Read()) { this.TimeLabel.Text = string.Format("database time: {0}", reader["Data"].ToString()); } } }

# by Jeffrey

to 狐狸俊, command.Parameters.Add(":p1", "aa");<=參數名稱要加上分號。

# by 狐狸俊

to 黑大: 我從沒加過也正常吶,無論是 SqlServer 的 @ 或 Oracle 的 :, 只要把 where 那一行改成 where ('aa' = :p1) 就正常執行了,所以以想請教你為什麼?

# by Jeffrey

to 狐狸俊, Sorry,先前沒看清楚你的程式,問題出在ODP.NET的OracleCommand.BindByName預設為false,意思是依Parameter在SQL語法的出現順序與Parameters.Add的加入順序配對,而不是依參數名稱。 如果SQL中:p1跟:p2各出現兩次( 如 'aa' = :p1 or :p1 is null),Paramters.Add時要加入兩次p1,兩次p2(名字不重要,順序要對)。如果想用變數名稱匹配,可將BindByName設為true(我習慣一律設true),如此行為就會跟SqlCommand一致。 補充:http://goo.gl/ELeCz3

# by 狐狸俊

to 黑大: 瞭解了,謝謝,獲益良多。

# by Sam Zhong

to 黑大: 我最近也使用了這個強大的元件,並配合Dapper來做Oracle資料存取。 但有個是關於Oracle語系 NLS_LANG 的設定問題,導制資料查詢後中文出現亂碼,這部份是否有比較標準的設定方式呢?

# by Jeffrey

to Sam Zhong, 問,DB欄位是用NVarChar2? 如果是用VarChar2,NLS_LANG要設成你資料連用的語系,如果是NVarChar2,經驗裡很少有問題,除了 ODP.NET + Dapper 的一個小Bug:http://blog.darkthread.net/post-2016-08-21-dapper-odpnet-unicode-issue.aspx

# by Sam Zhong

to 黑暗大: 感謝您的回應,目前暫時解法是客戶本機端提供OracleClient 環境,我程式直接改用OleOracle的連線提供者去連接資料庫。 Odp.Net的方法我再找時間測試,通常這種情形真的很罕見

# by Leovinci

請教暗黑大: 不知您是否遇到 只要VisualStudio 更新升級完後,Server Explorer 裡面建立的Oracle Entity Model 的連線就會失敗,會跳出錯誤訊息說沒有安裝ODP.Net,去StackOverflow 找答案 知道要去 machine.config 新增DbProviderFactories,可是重複前面步驟又跳出新的錯誤訊息 An unexpected error occurred in the ODP.NET, Managed Driver. Please contact the provider vendor to resolve this problem.The data provider has no IVsDataConnectionSupport implementation. 就找不到相關解法了,我知道只要重新安裝ODAC 就可解決,但VS更版的速度滿頻繁的,老是重灌ODAC不是辦法,所以想請教您可有不用重灌ODAC的解法? 微軟的SQLServer就沒這問題,很明顯的是微軟耍小手段排擠Oracle 啊 XD

# by Jeffrey

to Leovinci,我很久沒用 ODAC 了(Dapper 無敵 :P),難怪無感。爬文有查到相關回報 https://community.oracle.com/thread/4184518,網友的解法也是重裝。

# by Leovinci

To Jeffrey,剛查了您說的Dapper,看起來是個了不起的東西呢,不知是否一樣可支援Oracle 且使用Database Firsst 的方式來產生Entity Model,並支援LINQ To Database 和使用LINQ method 搭配Lambda 語法? 有相關教學資源可供參考嗎? 感謝您的回覆。

# by Jeffrey

to Leovinci, 如果你希望用 LINQ to DB,仍需依賴 EF。Dapper 的強項在於不需事先產生 Entity Model 及可以完全掌握 SQL 語法,與 EF 標榜的強型別、LINQ、跨 DB 正好相反,二者如何抉擇見仁見智。 我的觀點傾向二者併用,查詢及批次更刪用 Dapper、單筆資料增改再考慮EF,更多闡述可參考這篇:https://blog.darkthread.net/blog/linq-or-direct-sql/

# by Leovinci

To Jeffrey,誠如您所述,我昨日又大致再看了一下Dapper的相關資訊和用法,確實Dapper真是短小精悍,雖然EF的DB First自動產出 EntityModel方便,但實務上卻還是要以自己編寫的Model為最後產出,而Dapper則是要什麼Model自己產出,主要是幫開發者節省連線資料庫和跑迴圈逐一塞值到Model裡面,所以我後續應該會來使用看看這一套件,感謝您的推薦。 但我之所以喜歡EF 和Lambda LINQ to SQL,其實是因為SQL這玩意很缺乏邏輯編碼的體驗(其實是自己不太會寫SQL... XD),程式寫著寫著卻突然要插入一長串SQL,看了實在礙眼,不如Lambda的直覺和簡潔,所以對EF難以割捨啊~~

Post a comment


65 + 19 =