如何解決 Oracle ORA-00904: “FALSE” 無效的 ID 錯誤?完整解析與三種實戰方案

 

前言

在使用 .NET 與 Entity Framework Core 連接 Oracle 資料庫時,常會遇到一個看似莫名其妙的錯誤訊息:

OracleException: ORA-00904: "FALSE": 無效的 ID
如果你不是資料庫專家,看到這裡可能會疑惑:「為什麼寫程式時只是用到 C# 裡的 false,居然跑到 SQL 裡變成了 FALSE,而 Oracle 不認得?」本篇文章將深入淺出,帶你了解其成因,並提供三種可行的解決方案,讓你快速排除故障、恢復正常開發流程。


為什麼會發生 ORA-00904: “FALSE” 無效的 ID?

  1. Oracle 不支援 Boolean
    在 Oracle 的 SQL 語言裡,並沒有像 TRUEFALSE 這樣的布林(Boolean)字面量。

  2. EF Core Provider 自動翻譯
    當你在 LINQ 查詢或投影中使用了 C# 的布林值(例如 p => p.APS_DEAL ? "Y" : "N" 或直接把 bool 欄位投影),Oracle 的 EF Core 外掛在產生 SQL 時,會把 false/true 翻譯成 FALSE/TRUE,這就觸發了「無效的 ID」錯誤。



解法一:在記憶體端處理投影(Pull then Project)

概念:先把純資料實體取回(不帶任何方法呼叫),再用 LINQ-to-Objects 做 ToString()、三元運算、bool→字串、格式化等邏輯。

// 1) 把實體一次查回
var plans = await _context.APSZPLANs
    .Where(p => p.APS_VERSION == apsVersion)
    .ToListAsync();

// 2) 在 C# 記憶體端再投影
var result = plans.Select(p => new APSZRESULTA
{
    APS_PLAN_NO  = p.APS_PLAN_NO,
    // 把布林轉成字串
    APS_DEAL     = p.APS_DEAL ? "Y" : "N",
    APS_DEAL_QTY = (p.APS_DEAL_QTY ?? 0).ToString("N0"),
    // 其他欄位同理…
}).ToList();

優點:完全不會再觸發 Oracle 的 FALSETRUE,簡單易懂。
缺點:資料先拉大宗到客戶端,若筆數很多可能效能受影響。



解法二:在查詢中插入 .AsEnumerable()

概念:透過 .AsEnumerable() 把查詢由 EF Core 轉為 LINQ-to-Objects,之後的 Select 都在記憶體裡執行。

var interim = await _context.APSZPLANs
    .Where(p => p.APS_VERSION == apsVersion)
    .OrderBy(p => p.APS_PLAN_NO)
    .AsEnumerable()      // ← 斷開 EF Core 翻譯
    .Select(p => new APSZRESULTA
    {
        APS_PLAN_NO  = p.APS_PLAN_NO,
        APS_DEAL     = p.APS_DEAL ? "Y" : "N",
        APS_DEAL_QTY = (p.APS_DEAL_QTY ?? 0).ToString("N0"),
        // …其他欄位
    })
    .ToListAsync();
優點:比第一種方法更有彈性,能保留 SQL 的 WHEREORDER BY
缺點:在 AsEnumerable() 之前撈出的資料量仍會傳到客戶端。



解法三:使用 EF Core ValueConverter 將 Boolean 映射成數字或字串

概念:在 OnModelCreating 中,透過 ValueConverter 把 C# 的 bool 欄位映成 Oracle 能接受的型別(如 NUMBER(1)CHAR(1))。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(e => e.APS_DEAL)
        .HasConversion(
            v => v ? 1 : 0,        // C# → 資料庫 存成 0/1
            v => v == 1           // 資料庫 → C# 還原成 bool
        )
        .HasColumnType("NUMBER(1)");
}

優點:資料庫層面就統一將布林轉 0/1,不需額外在每個查詢裡寫三元運算。
缺點:需調整 DbContext 映射設定,對現有資料庫 schema 可能有影響。



小結與建議

  • 如果專案筆數規模不大,建議優先選擇 解法一解法二,最快速解決 SQL 產生 FALSE 的問題。

  • 如果你希望長期維護更乾淨的映射,並避免在各處重複轉換邏輯,可考慮 解法三,在 OnModelCreating 做一次性設定。

了解了 Oracle 不支援 Boolean,並掌握上述三種策略,就能有效消除 ORA-00904: "FALSE": 無效的 ID,讓你的 .NET + 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 為例