🗄️如何解決 Oracle 連線失敗與 Entity Framework decimal 精度警告|詳細教學
內容
一、前言
在開發企業級應用時,常見會用到 Oracle 資料庫搭配 Microsoft 的 Entity Framework Core (EF Core)。近日在專案中出現兩大挑戰:
-
ORA-12541 / ORA-50201 / ORA-50000:與 Oracle 監聽器 (Listener) 通訊失敗,導致無法連線。
-
大量 decimal 精度警告:EF Core 在自動產生模型時,發現多個
decimal
欄位沒指定精度 (precision) 與小數位 (scale),提醒可能有截斷風險。
以下將以「軟體工程師解釋給門外漢」的方式,一步步拆解兩個問題成因並提供完整解方。
二、問題一:Oracle 監聽器連線失敗
2.1 錯誤訊息
ORA-12541: TNS:無聲音響應 ORA-50201: Failed to connect to server or failed to parse connect string ORA-12514: Service … is not registered with the listener ORA-50000: Connection request timed out
這些錯誤代表應用程式無法透過 TCP/IP(預設 1521 埠)跟 Oracle 監聽器建立連線。
2.2 核心原因
-
Listener 沒啟動:Oracle 監聽器程式(
lsnrctl
)不在執行,或正在監聽錯誤的 IP/Port。 -
服務沒向 Listener 註冊:Oracle 實例未自動註冊到監聽器,監聽器無法管理此資料庫。
-
網路防火牆或本機防火牆封鎖:TCP 1521 埠被攔截。
-
連接字串錯誤:
tnsnames.ora
或直寫的 Connect Descriptor 內參數重複、拼錯。
2.3 解決步驟
-
確認 Listener 狀態
lsnrctl status # 若未啟動,執行: lsnrctl start
確保「STATUS: READY」且「Services Summary」列出你的 SERVICE_NAME(例:INX_APS)。
-
調整 listener.ora
檔案位置:$ORACLE_HOME/network/admin/listener.ora
LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521)) ) )
-
HOST=0.0.0.0
等同於「監聽所有網路介面」。 -
修改後重啟監聽器:
lsnrctl stop lsnrctl start
-
-
確認資料庫實例註冊
請以sqlplus / as sysdba
登入,執行:ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=220.133.47.3)(PORT=1521))' SCOPE=BOTH; ALTER SYSTEM REGISTER;
然後再用
lsnrctl status
,Service Name 應該出現INX_APS
。 -
排除防火牆干擾
-
Windows/iptables 防火牆允許入站 TCP 1521
-
從客戶端用 PowerShell 測試:
Test-NetConnection -ComputerName 220.133.47.3 -Port 1521
-
若失敗,請網管開通。
-
-
使用 tnsping 驗證
確保tnsnames.ora
中的連接描述正確:INX_APS = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 220.133.47.3)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = INX_APS)) )
再執行:
tnsping INX_APS
三、問題二:Entity Framework decimal 精度警告
3.1 警告內容
The decimal property 'A052' on entity type 'APS_Z_LCM_QTY' does not have a store type specified. This may lead to a precision loss…
EF Core 無法自動推知 Oracle 資料庫裡
NUMBER(p,s)
的 p、s
值,一律套用預設值。若欄位實際儲存需求超過預設,將造成資料刪尾或錯誤。
3.2 核心建議
Oracle 官方建議在
OnModelCreating
裡,透過下列
API 明確指定:
-
HasColumnType:直接寫完整型別
NUMBER(18,6)
-
HasPrecision:只定
precision
與scale
-
HasConversion:若想轉成其他 C# 型別
3.3 範例程式碼
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => { // 單欄位指定 entity.Property(e => e.A052) .HasColumnType("NUMBER(18,6)"); entity.Property(e => e.OBJID) .HasPrecision(12, 0); // 批次自動為所有 decimal 欄位設定 foreach (var prop in typeof(APS_Z_LCM_QTY).GetProperties() .Where(p => p.PropertyType == typeof(decimal) || p.PropertyType == typeof(decimal?))) { modelBuilder.Entity () .Property(prop.Name) .HasPrecision(18, 6); } }); }
⚠️ 注意:若
decimal
欄位被當作主鍵 (Key),更應確保 scale=0,或考慮改用整數/字串欄位以免潛在誤差。
四、結論
透過上述步驟,你可以同時解決:
-
Oracle 監聽器連線不通:確保 Listener 啟動、服務註冊、網路通暢、連接字串無誤。
-
EF Core decimal 精度警告:在
OnModelCreating
明確指定HasColumnType
/HasPrecision
,避免未來資料截斷風險。
兩者問題解決後,重新啟動應用即可恢復正常連線並消除警告。希望這篇詳細教學對你有幫助,下次遇到 Oracle + EF Core 問題,一看就懂!
留言
張貼留言