Wrong. FieldCount is NOT the same as RecordCount. These are two completely different things. While FieldCount gives you the number of
fields inside the record, RecordCount gives you the number of
records inside a Dataset.
For example, if we had a record with 3 fields:
(ID=0;CreateTime=2010-2-2 8:30:00;Name=RTC)
Assuming this record is stored in the variable rec:TRtcRecord, then:
rec.FieldCount will return 3,
rec.FieldName[0] will return 'ID',
rec.FieldName[1] will return 'CreateTime'
and FieldName[2] will return 'Name'.
To check the type of each field, you will use the "isType" property. And to access the value of each field, you will use the "as" property depending on the field type. So, assuming the structure from above, we would get ...
rec.isType[ rec.FieldName[0] ] will return one of the numerical types like rtc_Integer, rtc_LargeInt or rtcFloat, depending on the property used to assign the value on the other side, while rec.isType[ rec.FieldName[1] ] will return rtc_DateTime,
and rec.isType[ rec.FieldName[2] ] will return rtc_String, rtc_Text or rtc_WideString, also depending on the property used on the other side to assign the value on the other side.
To access the value of each field inside our record, we should use the correct "as..." property (asString, asInteger, asText, asFloat, asDateTime) so we do not have to worry about string conversions. Doing this for the above record structure ...
rec.asInteger[ rec.FieldName[0] ] will return 0,
rec.asDateTime[ rec.FieldName[1] ] will return the correct TDateTime value for February 2nd 2010 at 8:30 AM,
and rec.asText[ rec.FieldName[2] ] will return the string 'RTC'.
Please note that you should not mix "asString" with "asText" or "asWideString", because each of these types have distinctive meaning, especially in Delphi 2009 and later. While "asString" is ALWAYS of native Delphi type AnsiString and is primarily used for sending binary data strings and not humanly readable text, "asWideString" works with Wide Strings (binary coded 2-byte strings), and "asText" is the native UnicodeString in Delphi 2009 which will be automatically encoded and decoded using the UTF-8 standard, or a simple AnsiString in Delphi 2007 and later which will be encoded and decoded using current local regional settings of the PC the application is running on.
On the other end, if you do not care about the actual types contained in your record, but just want to print the data out to a log file, you could assume that all the fields in your record are of a simple value type (NOT record, array or dataset) and just use the "asString" property for them all.
Let's say you use the RTC SDK to create a record on one side and then want to read it out on the other side. To create the above record and send it as a result of your RTC remote function from the Server, you would use something like:
with Result.newRecord do
begin
asInteger['ID']:=0;
asDateTime['CreateTime']:=Str2DateTime('2010-2-2 8:30:00');
asText['Name']:='RTC'; // to send binary data, use "asString" or "asByteStream"
end;
And to read it out on the other side, without knowing the names of your fields inside the record (ID,CreateTime,RTC), you would use FieldCount and FieldName properties like this:
var
n:integer;
rec:TRtcRecord;
fname:String;
begin
if Result.isType=rtc_Record then
begin
rec:=Result.asRecord;
Log('Received record with '+IntToStr(rec.FieldCount)+' fields:');
for n:=0 to rec.FieldCount-1 do
begin
{ get the name of the n-th field: }
fname:=rec.FieldName[n];
{ To keep this example short, I will blindly assume that all the fields in
my record are of a simple type (integer, string, float, datetime).
To keep it even shorter, I will use the RTC SDK capability to
convert any simple type (Integer, DateTime, String or Double) into
a string, so I do not have to check each type for using it in Log().
I will also use the "rtcTypeName" RTC function to get the full
name of a type, just to simplify things in this example. Normally,
you would use the value returned from "isType" to know how you
can directly access the field using its type (Integer, DateTime, etc)
through the exact same properties you have used to assign them. }
Log( 'FieldName='+fname+
'; FieldType='+rtcTypeName(rec.isType[fname])+
'; FieldValue='+rec.asString[fname]);
end;
end;
If, for example, you would also want to handle fields of the type "rtc_array" and out all fields inside any array stored inside your record (please note that each field inside any complex structure like the record can also be an array, record, dataset or even a function call), you could extend the above example code to something like ...
var
n, a:integer;
rec:TRtcRecord;
arr:TRtcArray;
fname:String;
begin
if Result.isType=rtc_Record then
begin
rec:=Result.asRecord;
Log('Received record with '+IntToStr(rec.FieldCount)+' fields:');
for n:=0 to rec.FieldCount-1 do
begin
{ get the name of the n-th field: }
fname:=rec.FieldName[n];
{ This is a simple example, so I will not be really using the data in the
record for anything but printing it out to a Log file, so I can use the
'isSimpleValue' function from the rtcInfo unit to check that the type
of RTC object received is simple (does not contain sub-objects): }
if isSimpleValue(rec.asObject[fname]) then
begin
{ For simplicity, I will use the feature of the RTC SDK to automatically
convert any simple type (Integer, DateTime, String or Double) into
a string, so I do not have to check each type for using it in Log().
I will also use the "rtcTypeName" RTC function to get the full
name of a type, just to simplify things in this example. Normally,
you would use the value returned from "isType" to know how you
can directly access the field using its type (Integer, DateTime, etc)
through the exact same properties you have used to assign them. }
Log( 'FieldName='+fname+
'; FieldType='+rtcTypeName(rec.isType[fname])+
'; FieldValue='+rec.asString[fname])
end
else
begin
{ Our field is of a complex type like a Record, Array or DataSet ... }
{ You can use the "isType" property to check what type each field has
to access its data using the appropriate "as..." method. Here, I will
only do this for arrays, but the principle is the same for records inside
fields as it is for records standing alone, and this is only a simple example,
so I will not be repeating the same code I already wrote above for records. }
if rec.isType[fname]=rtc_Array then
begin
Log('FieldName='+fname+
'; FieldType='+rtcTypeName(rec.isType[fname])+
'; (sub)FieldCount='+IntToStr(rec.asArray[fname].Count)+' fields:');
{ For simplicity, I will use a local variable to access the field (which is an array): }
arr:=rec.asArray[fname];
for a:=0 to arr.FieldCount-1 do
begin
{ Since array fields do not have names, but are accessed through
their integer index, we will not need the FieldName property to
access fields of the array, but can simply use the field index. }
Log('Element '+IntToStr(a)+
' Field Type='+rtcTypeName(arr.isType[a])+
'; FieldValue='+arr.asString[a]);
end;
end
else
begin
{ This example has already gotten a lot larger than it should be,
so - for all other types, I will just print out the name and type: }
Log('FieldName='+fname+'; FieldType='+rtcTypeName(rec.isType[fname]);
end;
end;
end;
end;
The code above uses the "rtcInfo.pas" and "rtcLog.pas" units from the RealThinClient SDK.
In addition to the "isSimpleValue", "isSimpleValueType" and "rtcTypeName" functions, there are a number of other useful functions in the "rtcInfo.pas" unit. Each function has its declaration and a short description in the interface section of the unit, which can also be found in the HELP file for the "rtcInfo" unit.
You will also find several versions of thread-safe "Log" and "xLog" functions (can be used without hesitation inside a multi-threaded client and server), which can be used for debugging and information logging in your RTC Clients and Servers.
I hope this explanation was detailed enough. Should you need more information, please look into the HELP file, check the source code or search freely available documentation from the RTC SDK Archive:
http://www.realthinclient.com/sdkarchiveBest Regards,
Danijel Tkalcec