🔍【深入解析】解決 Oracle EF Core 報錯「ORA-00904: 'FALSE': 無效的 ID」的終極指南
1. 錯誤現象與訊息解讀
你在用 .NET EF Core 撰寫資料存取層(Repository)時,執行 Oracle 查詢時突然爆出:
Oracle.ManagedDataAccess.Client.OracleException (0x80004005): ORA-00904: "FALSE": 無效的 ID
這段英文翻譯是「FALSE:無效的識別字(ID)」,也就是 Oracle 資料庫根本不認得
"FALSE"
這個東西。
2. 報錯主因:EF Core 與 Oracle 的布林陷阱
EF Core 在 SQL Server 或 MySQL 下支援
TRUE/FALSE
常數,但Oracle 完全不支援布林常數。
只要你在 LINQ to Entities 查詢裡「產生布林運算」——例如:
select new DTO { IsValid = (someCondition) }
EF Core 會把這段程式碼自動轉換成 SQL:
CASE WHEN ... THEN True ELSE False END
Oracle 完全不認得 True
、False
這兩個關鍵字,導致
ORA-00904
直接報錯!
3. 常見誤區:C# 條件運算與三元運算
你以為 assign 給 string 型別就安全?
其實只要你在 select new {...} 內寫條件判斷(? :
)、ToString()、或 DateTime.MinValue 判斷,
EF Core 都會自動轉成 Oracle 看不懂的 SQL。
錯誤寫法:
ORI_PLAN_DATE = (z.ORI_PLAN_DATE == null || z.ORI_PLAN_DATE == DateTime.MinValue) ? null : z.ORI_PLAN_DATE.Value.ToString("yyyy-MM-dd")
這會導致 Oracle 端產生
CASE WHEN (...) THEN True ELSE False END
報錯收場!
4. 實戰案例 — 專案程式碼片段分析
典型 select new 錯誤範例
var query = from z in _context.Table select new DTO { // 這裡一用條件式就爆炸 IsNull = (z.SOME_DATE == null) };
錯誤訊息
ORA-00904: "FALSE": 無效的 ID
5. 如何正確解法?三步驟徹底根治
Step 1. 不要在 LINQ 查詢(IQueryable)用條件運算與 C# 特有語法。
Step 2. 只 select
出原始欄位,資料抓進記憶體(ToList/AsEnumerable)後再做運算。
Step 3. DTO 型別完全不要用 bool,只用 int 或 string。
修正後最佳寫法
// 1. 先查出 List var dataList = await _context.Table.Where(...).ToListAsync(); // 2. 再用 C# 處理運算與格式 var result = dataList.Select(z => new DTO { IsNull = (z.SOME_DATE == null) ? 1 : 0, ORI_PLAN_DATE = (z.ORI_PLAN_DATE == null || z.ORI_PLAN_DATE == DateTime.MinValue) ? "" : z.ORI_PLAN_DATE.Value.ToString("yyyy-MM-dd") }).ToList();
6. 最佳實踐與預防建議
-
所有布林條件判斷,轉成 1/0 或 "Y"/"N" 字串存 DTO
-
資料庫查詢端只做簡單 select,不要做三元運算、ToString()、日期格式轉換等 C# 行為
-
Model/DTO 層不用 bool 型別,完全用 int/string 替代
7. 常見Q&A
Q1:為什麼 SQL Server 沒這問題,Oracle 卻會報錯?
A1:SQL Server/MySQL 支援
TRUE/FALSE
常數,Oracle 僅支援
1/0
或
'Y'/'N'
,
EF Core 產生 SQL 時沒幫你自動轉換,就會報錯。
Q2:除了條件運算,還有什麼會讓 Oracle 報 ORA-00904?
A2:任何 Oracle 不認得的識別字(如欄位拼錯、用保留字、還有 select new 產生 bool 結果)都會報這個錯。
8. 結語
只要你遇到 EF Core + Oracle 報 "ORA-00904: 'FALSE': 無效的 ID"
第一步檢查 select new {...} 有沒有用到條件運算或 assign bool,全部改成
int/string,並把複雜運算移到記憶體運作階段,保證一勞永逸!
留言
張貼留言