我在Delphi XE5中构建了一个使用Rest库的delphi客户端示例:
所有由ASP.net Web API提供服务,该API根据Delphi的动态查询生成数据集。我可以成功运行查询并将数据返回给客户端并呈现数据,但是布尔字段呈现为空白。
修改 令人惊讶的是,Embarcadero的TRestResponseDatasetAdapter在内部执行此操作以创建字段:
procedure TCustomJSONDataSetAdapter.CB_CollectFieldDefs(const AJSONObject: TJSONObject);
var
LJSONPair: TJSONPair;
begin
for LJSONPair in AJSONObject do
begin
DoAddDataSetFieldDef(LJSONPair.JsonString.Value, ftString);
end;
end;
字段类型都是硬编码到ftString!
这是返回的json:
"Table": [
{
"Id": 34,
"Node": "Navision_ASN_1",
"FormatId": 2,
"Value": null,
"ParentID": null,
"DocumentOrder": 1,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 35,
"Node": "MessageHeader",
"FormatId": 2,
"Value": null,
"ParentID": 34,
"DocumentOrder": 2,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 52,
"Node": "Consignment",
"FormatId": 2,
"Value": null,
"ParentID": 34,
"DocumentOrder": 13,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 53,
"Node": "Line",
"FormatId": 2,
"Value": null,
"ParentID": 52,
"DocumentOrder": 18,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
}
]
答案 0 :(得分:1)
你不能!
问题归结为Embarcadero Delphi的TJsonObject类。在Rest.Response.Adapter单元中,返回的json被解析为TJsonObject,然后在CB_CollectFieldDefs和CB_CollectFieldData中迭代对象中的所有TJsonPairs。
第一个问题:CB_CollectionFieldDefs将ftString硬编码为要添加到每个字段定义的dataSet的数据类型。所以我从Web API调用中返回了字段类型,以消除猜测并手动构建字段定义。当RestResponseDataSetAdapter具有字段定义时,单元正确跳过CB_CollectionFieldDefs,这导致第二个问题。
Second problem:对象中的TjsonPair没有正确解析布尔json值。到调用CB_CollectFieldData时,应该是变量类型的所有布尔值都是空字符串。所以我们得到异常'无法将类型(UnicodeString)的变体转换为类型(布尔)'。
我遗憾地不得不放弃这一有前途的组件,转而支持Fabricio Colombo's优秀的休息客户端api。使用他的GetAsDataSet逻辑中的模式,我创建了一些post方法来发布json(因为从内置delphi单元创建的json是不正确的,我用SuperObject代替)。我introduced PostJson and CreateDataset都返回TClientDataSets。
function TResource.CreateDataset(data: string; table: string = ''; titles: string = ''): TClientDataSet;
var
vJson: ISuperObject;
begin
vJson := SuperObject.SO(data);
Result := TJsonToDataSetConverter.CreateDataSetMetadata(vJson, table, titles);
TJsonToDataSetConverter.ToDataSet(Result, vJson.O[table]);
end;
// which allows me to do:
ds := jsonrestclient1.Resource(url)
.ContentType(RestUtils.MediaType_Json)
.Accept(restutils.MediaType_Json)
.PostJson(json, 'Table', 'Titles');
// or
rs := jsonrestclient1.Resource(url)
.ContentType(RestUtils.MediaType_Json)
.Accept(restutils.MediaType_Json);
data:= rs.PostJson(Query) ;
vJson := SO(data);
fHasMore := vJson.B['HasMore'];
ds:= rs.CreateDataset(data, 'Table', 'Titles');