LINQ to Entities (Oracle)遇到ORA-12074錯誤的處理方式

  • 5717
  • 0
  • 2012-12-20

LINQ to Oracle遇到ORA-12074錯誤的處理方式

Dotblogs 的標籤: , , ,

今天遇到的問題,搞了我三個小時,趕快記下來……

LINQ to Entities (Oracle),使用的 Provider 是 ODAC 11.2 Release 4 (11.2.0.3.0),資料庫是 Oracle 11g,用 LINQPad 測試。

問題是:使用 LINQ 查詢資料時,有個欄位可能是 null 值,所以在投影(Select)時要轉成其他替代字串,但是執行時,會發生 ORA-12074 的錯誤。

先講測試到目前的結論:除非真的有其必要性,否則在 LINQ to Entities (Oracle) 投影時(Select),不要做任何替代的動作,真的輸出時,再執行 null 替代為對應字串的情形(null ?? “[null]”)。

接著來看我這次研究的記錄。一開始下的 LINQ 和執行結果:

160051

完全摸不著頭緒的錯誤訊息,當然就只能請苦狗大師回答囉!看了好久,一直無法找出原因,乾脆把 ODAC 產出的 SQL 倒出來看:

SELECT 
1 AS "C1", 
"Extent1"."ID" AS "ID", 
CASE WHEN ("Extent1"."ADDRESS" IS NULL) THEN '[null]' ELSE "Extent1"."ADDRESS" END AS "C2"
FROM "SA"."LEO_TEST" "Extent1"

好像沒什麼問題啊,那就丟到 Oracle Command line 執行,結果也出現同樣的 ORA-12074 錯誤,所以的確是 SQL 中有問題。因為接觸 Oracle 以來,三不五時就會被 Unicode 的狀況打到,所以馬上調 Table 結構出來看,果不其然,Address 欄位是 NVarchar2:

create table LEO_TEST
(
  id        VARCHAR2(40) not null,
  address   NVARCHAR2(1000),
  v2address VARCHAR2(1000),
  n1        NUMBER,
  n2        NUMBER
);
alter table LEO_TEST
  add constraint PK_LEO_TEST primary key (ID)
  using index;

所以上述的 SQL 的問題是在若為 Null,要給新字串做替代的部分:

錯誤:THEN '[null]'

正確:THEN N'[null]'

但是這個 SQL 是 ODAC 的 Entity Framework 所產出的,我怎麼強迫他用 N'[null]' ?目前我找不到答案,嚐試錯誤多次後,最後是以下列方式處理:

162845

上述命令,轉換出來的 SQL Script 如下:

SELECT 
1 AS "C1", 
"Extent1"."ID" AS "ID", 
CASE WHEN ("Extent1"."ADDRESS" IS NULL) THEN :p__linq__0 ELSE "Extent1"."ADDRESS" END AS "C2"
FROM "SA"."LEO_TEST" "Extent1"
WHERE ("Extent1"."ADDRESS" IS NULL)

我們會發現,string.Empty 會變成一個 Oracle Command 的 parameter,名為 p__linq__0。因為帶的是參數,固定會是 Unicode 的格式,所以避開了字串沒有加 Unicode 標記「N」的問題,然後實際輸出時,再用「??」運算子將空值轉成要替代的字串。

但是這樣又讓我聯想到另一個問題,因為 string.Empty 會以參數方式帶入 SQL,預設是 Unicode,那如果這個欄位是 Varchar2,而非 NVarchar2,會怎樣?所以上述 Table 開了 v2address 欄位做測試,結果悲慘:

171814

所以目前測試,若要在投影時(Select)就要做 null 替代,該欄位是 NVarchar2,那要先用 string.Empty,在輸出時再轉換成替代字串;若欄位型別是 Varchar2,就【不能】用 string.Empty,必須直接用字串去替代。

--------
沒什麼特別的~
不過是一些筆記而已