【茶包射手日記】安裝ODAC 11.2 Release 5後Visual Studio無法使用Oracle資料來源
使用Visual Studio 2012已經好一陣子,手上的專案也逐一改用VS2012維護開發。今天處理的專案剛好涉及Oracle,想當然爾,要用Entity Framework才是王道! 此時發現原先安裝的ODAC 11.2 Release 4,只支援到VS2010,在VS2012新增ADO.NET Entity Data Model時,Data source沒有"Oracle Database (Oracle ODP.NET)"可選,所幸Oracle已於9/11推出ODAC 11.2 Release 5,加入對VS2012的支援。
二話不說,立刻下載安裝!


安裝過程很順利,正要為Oracle按個讚之際,卻發現VS2012要新增ADO.NET Entity Data Model時還是沒有Oracle可選。想對照比較,還更進一步發現,在安裝完Release 5後,VS2010的Server Explorer要新增連線時,雖然可選擇Oracle Database (Oracle ODP.NET),但其【OK】鈕呈現灰色停用狀態,無法新增。(相關操作請參考前文) 按下【Test Connection】鈕,則會彈出錯誤: Unable to find the requested .NET Framework Data Provider. It may not be installed.

我的推測是在安裝ODAC 11.2 Release 5後,某些設定被改壞了,不但VS2012沒法用Oracle EF,連VS2010原本可用的功能也壞了~
試著重新安裝Oracle Developer Tools for Visual Studio並無幫助(不過現在回想,我只試了重新安裝,沒有試過"先解除安裝再安裝一次",如果有朋友做過相同實驗,請再回報結果)。改由錯誤訊息下手,爬文後,對.NET DbProviderFactories機制多了一丁點了解,並在一番嘗試後終於解決問題。
[2012-10-31更新] 網友Dino回報"先移除ODAC 11.2 Release 4再安裝ODAC 11.2 Release 5,VS2010/VS2012均可順利使用無異常",在此感謝!
原來,.NET可以使用哪些Data Source,跟\Windows\Microsoft.net\Framework\vXXXX\Config\machine.config有關,在其中有一段DbProviderFatories宣告: (以下擷取自v2.0.50727\config\machine.config)
<system.data>
<DbProviderFactories>
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
<add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
....省略...
</DbProviderFactories>
</system.data>
在ODT或EF Data Model要新增連線時,Data Source可選項目看起來與其宣告的項目吻合。而我們可用以下程式列出所有DbProviderFactory加以驗證: [參考來源]
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
System.Data.DataTable dt =
DbProviderFactories.GetFactoryClasses();
for (int i = 0; i < dt.Rows.Count; i++)
Console.WriteLine("{0}: {1}", i.ToString(),
dt.Rows[i][2].ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.Read();
}
}
}
(注意: 因為Visual Studio本身是32位元.NET程式,記得以上程式Target要設成x86,顯現結果才會與Visual Studio IDE所見一致)
使用VS2012以.NET x86 Console Application執行上述程式,果真沒有Oracle.DataAccess.Client!
0: System.Data.Odbc
1: System.Data.OleDb
2: System.Data.OracleClient
3: System.Data.SqlClient
4: System.Data.SqlServerCe.4.0
檢查\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config,卻發現其中只有SQL Client CE一個項目: (但為什麼列舉結果中還是有Odbc, OleDb, SqlClient, System.Data.OracleClient? 我查到一篇討論,MSFT Support表示4.0起另有機制可動態取得.NET Framework內建的SqlClient及OracleClient,不需依賴machine.config設定)
<system.data>
<DbProviderFactories>
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
</DbProviderFactories>
</system.data>
推敲此處應放入.NET 4.0版本的Oracle.DataAccess.Client設定,因此我手動補上(紅字部分):
<system.data>
<DbProviderFactories>
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
</DbProviderFactories>
</system.data>
加入後重跑前述DbProviderFactory列舉程式,Oracle.DataAccess.Client便已名列其中,在重新啟動VS2012後,Data Source選擇視窗已有Oracle Client可選,ADO.NET Entity Data Model也能順利新增Oracle EF Data Model囉~