🗄️如何解決 Oracle 連線失敗與 Entity Framework decimal 精度警告|詳細教學

內容

一、前言

在開發企業級應用時,常見會用到 Oracle 資料庫搭配 Microsoft 的 Entity Framework Core (EF Core)。近日在專案中出現兩大挑戰:

  1. ORA-12541 / ORA-50201 / ORA-50000:與 Oracle 監聽器 (Listener) 通訊失敗,導致無法連線。

  2. 大量 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 核心原因

  1. Listener 沒啟動:Oracle 監聽器程式(lsnrctl)不在執行,或正在監聽錯誤的 IP/Port。

  2. 服務沒向 Listener 註冊:Oracle 實例未自動註冊到監聽器,監聽器無法管理此資料庫。

  3. 網路防火牆或本機防火牆封鎖:TCP 1521 埠被攔截。

  4. 連接字串錯誤tnsnames.ora 或直寫的 Connect Descriptor 內參數重複、拼錯。

2.3 解決步驟

  1. 確認 Listener 狀態

        lsnrctl status
        # 若未啟動,執行:
        lsnrctl start    

    確保「STATUS: READY」且「Services Summary」列出你的 SERVICE_NAME(例:INX_APS)。

  2. 調整 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
      
  3. 確認資料庫實例註冊
    請以 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

  4. 排除防火牆干擾

    • Windows/iptables 防火牆允許入站 TCP 1521

    • 從客戶端用 PowerShell 測試:

      Test-NetConnection -ComputerName 220.133.47.3 -Port 1521
      
    • 若失敗,請網管開通。

  5. 使用 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:只定 precisionscale

  • 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,或考慮改用整數/字串欄位以免潛在誤差。

 


四、結論

透過上述步驟,你可以同時解決:

  1. Oracle 監聽器連線不通:確保 Listener 啟動、服務註冊、網路通暢、連接字串無誤。

  2. EF Core decimal 精度警告:在 OnModelCreating 明確指定 HasColumnType / HasPrecision,避免未來資料截斷風險。

兩者問題解決後,重新啟動應用即可恢復正常連線並消除警告。希望這篇詳細教學對你有幫助,下次遇到 Oracle + EF Core 問題,一看就懂!



留言

這個網誌中的熱門文章

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題

🛠【實戰排除教學】從 VS Code 的 _logger 錯誤,到 PowerShell 找不到 npm/serve,再到 Oracle ORA-03135 連線中斷——一次搞懂!

🔎如何在 Oracle PL/SQL 儲存過程中為文字欄位加入換行符號(CHR(10))——以 Updlcmremark 為例