前情提要:Delphi 特規 JSON 和 JavaScript Object (1)
已知大匠可以將 Blob 型態轉為 Hex JSON Array,但容量會放大 4 倍是硬傷;而 Memo 型態卻也被視為 Blob 型態,導致傳輸內容更加地龐大,更有堪者,可達放大 6 倍之譜。
追綜原因
Delphi 轉換 JSON 封包主要是利用 TDBXJSONTools.TableToJSON 函式庫內容,它會利用 TDBXReader.ValueType 進行 Delphi Value to JSON Value 轉換:
JsonCell := DBXToJSON(Value.Value[I], Value.ValueType[I].DataType, IsLocalConnection);
而 DBXToJSON 裡對 DataType 解析,節錄如下:
case DataType ofStreamToJSON 就是轉換 HEX JSON Array 的關鍵,所以如何讓 DataType 認得 Memo / WideMemo 才是正解。
TDBXDataTypes.BlobType,
TDBXDataTypes.BinaryBlobType:
Result := StreamToJSON(Value.GetStream(True), 0, High(Integer));
TDBXDataSetReader 對 TDataSet 的轉換只會認得 BlobType,SubDataType 屬性並不會使用,有了這個方向,就可以開始追原始碼,接著修改 TableToJSON 函式:
TDBXDataTypes.BlobType,
TDBXDataTypes.BinaryBlobType:
case ASubDataTypes of
TDBXSubDataTypes.MemoSubType,TDBXSubDataTypes.MemoSubType:
Result := TJSONString.Create(Value.AsString);
else
Result := TDBXJSONTools.StreamToJSON(Value.GetStream(True), 0, High(Integer));
end;
結果出現:
依然轉換失敗,仔細一查,驚覺 SubDataTypes 為【0】,究竟是為什麼啊啊啊啊啊啊!(甩髮)。
再追 DBXDBReaders 單元
TDBXDataSetReader 包含 TDBXDBTable 類別,而它裡面有個【ToDataSubType】指定 TDBXSubDataType:
class function TDBXDBTable.ToDataSubType(FieldType: TFieldType): Integer;
begin
case FieldType of
ftWideMemo:
Result := TDBXDataTypes.WideMemoSubType;
else
Result := 0;
end;
end;
0 = TDBXDataTypes.UnknownType 未知類型。很好,Memo 在這裡不會被認識,所以要來開始動刀了嗎?
看到【This is not used directly by applications】就知道,這底層不是可以亂動的東西,就這樣結束整個追踪過程。
小結
Varchar(max) 必須先轉型為 NVarchar(Max) 才能正確轉出我們期待的 JSONString,而非 Hex JSON Array。
附帶說明
dbExpress 底層的 TDBXCommand 所轉出的 TDBXReader,因為有底層 Driver 的加持,所以 TDBXSubDataType 可以正確識別為 MemoSubType,所以會有以上的小結,大匠我想這可能是 TDBXDBTable 的小小小【Feature】,繞過就好。
被這無傷大雅的小小小【Feature】搞了數天,內心五味雜陳中。
後端的 JSON 搞定後,接下來就能專注在前端上,究竟前端 JS 要如何把 DJSON 轉為 JS Object 呢?
<< 未完待續 >>
See also
圖片來源:攝影師:Anna Shvets,連結:Pexels
沒有留言:
張貼留言