简体   繁体   English

如何获取动态TClientDataset(基于TRESTResponseDataSetAdapter)以正确识别布尔值?

[英]How do I get a dynamic TClientDataset (based on TRESTResponseDataSetAdapter) to correctly recognise boolean values?

I've built a delphi client sample in Delphi XE5 that utilises the Rest library: 我已经在Delphi XE5中构建了一个利用Rest库的delphi客户端示例:

  • TRestClient TRestClient
  • TRestRequest TRestRequest
  • TRestResponse TRestResponse
  • TRESTResponseDataSetAdapter TRESTResponseDataSetAdapter
  • TClientDataSet (and TDataSource bound to TDBGrid and TClientDataSet(和绑定到TDBGrid的TDataSource和
    TcxGridDBTableView) TcxGridDBTableView)

All served by an ASP.net Web API that generates a dataset based on dynamic queries from Delphi. 所有这些都由ASP.net Web API提供服务,该API根据来自Delphi的动态查询生成数据集。 I can successfully run the queries and return data to the client and render the data, however boolean fields are rendered blank. 我可以成功运行查询并将数据返回给客户端并呈现数据,但是布尔字段被呈现为空白。

  • How do I get TClientDataSet to recognise the data types correctly? 如何使TClientDataSet正确识别数据类型?
  • Is this the proper way to use the TRESTResponseDataSetAdapter or TClientDataSet? 这是使用TRESTResponseDataSetAdapter或TClientDataSet的正确方法吗?
  • Does anyone have any experience with these components 是否有人对这些组件有任何经验

EDIT Surprisingly, Embarcadero's TRestResponseDatasetAdapter does this internally to create fields: 编辑令人惊讶的是,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;

The field types are all hardcoded to ftString! 字段类型都被硬编码为ftString!

This is the returned json: 这是返回的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
        }
    ]

You can't! 你不能!

The issue comes down to the TJsonObject class from Embarcadero Delphi. 问题归结于Embarcadero Delphi的TJsonObject类。 In the Rest.Response.Adapter unit the json returned is parsed into a TJsonObject, and then all the TJsonPairs in the object are iterated over in CB_CollectFieldDefs and CB_CollectFieldData. 在Rest.Response.Adapter单元中,将返回的json解析为TJsonObject,然后在CB_CollectFieldDefs和CB_CollectFieldData中迭代对象中的所有TJsonPair。

First problem: CB_CollectionFieldDefs hardcodes ftString as the data type to add to the dataSet for each field definition. 第一个问题:CB_CollectionFieldDefs将ftString硬编码为要添加到每个字段定义的dataSet的数据类型。 So I returned the field types from my Web API call to remove the guesswork and built the field definitions manually. 因此,我从Web API调用中返回了字段类型,以消除猜测并手动构建了字段定义。 When the RestResponseDataSetAdapter has field definitions, the unit correctly skips CB_CollectionFieldDefs, this leads to the second problem. 当RestResponseDataSetAdapter具有字段定义时,该单元将正确跳过CB_CollectionFieldDefs,这将导致第二个问题。

Second problem : the TjsonPair in the object does not correctly parse boolean json values. 第二个问题 :对象中的TjsonPair无法正确解析布尔json值。 By the time CB_CollectFieldData is called, all the boolean values which should be variant types are empty strings. 到调用CB_CollectFieldData时,所有应该为变量类型的布尔值都是空字符串。 So we get the exception 'Could not convert variant of type (UnicodeString) into type (Boolean)'. 因此,我们得到了异常“无法将类型(UnicodeString)的变体转换为类型(Boolean)”。

I have sadly had to drop this promising set of components in favour of enhancing Fabricio Colombo's excellent rest client api. 可悲的是,我不得不放弃这套有希望的组件,以增强Fabricio Colombo出色的rest client api。 Using the pattern in his GetAsDataSet logic, I created a number of post methods to post json (since the json creation from built in delphi units were incorrect, I substituted with SuperObject). 使用他的GetAsDataSet逻辑中的模式,我创建了许多发布方法来发布json(因为从内置的delphi单元创建的json是不正确的,所以我用SuperObject代替了该方法)。 I introduced PostJson and CreateDataset which both return TClientDataSets. 介绍了PostJson和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');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM