RTC Forums
April 29, 2024, 04:41:01 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: How can loop (for or while) all data By TRTCInfo and TRTCRecord?  (Read 9094 times)
tintinsoft
Guest
« on: February 01, 2010, 04:47:20 AM »

How can loop (for or while) all data By TRTCInfo and TRTCRecord? The Method of TRTCInfo and TRTCRecord is a little.
I feel helpless.
If I(as Tourist ) ask some  question in Remobjects NewGroups,,RO Teams Will answer the question Soonly.
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: February 01, 2010, 11:34:43 AM »

Take a look at the FieldCount and FieldName properties on the TRtcRecord class (also available on TRtcInfo, which is a descendant of TRtcRecord). FieldName property is 0-based, which means that you will loop from 0 to FieldCount-1.

Best Regards,
Danijel Tkalcec
Logged
tintinsoft
Guest
« Reply #2 on: February 02, 2010, 02:10:46 AM »

I understand it,the FieldCount is the same as  "RecordCount",So it is easy to loop for RecordData.
But,If  I dont know the RtcRecord Strcut structure,Such as: (ID=0;CreateTime=2010-2-2 8:30:00;Name=RTC),
it is  Only solution to convert the string data to TStringList?
I am sorry,I cannot find the  mothod.can you help me ?
thhanks!
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: February 02, 2010, 06:25:21 AM »

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/sdkarchive

Best Regards,
Danijel Tkalcec
Logged
tintinsoft
Guest
« Reply #4 on: February 03, 2010, 01:51:44 AM »

It is very good,thank you very much!
Logged
tintinsoft
Guest
« Reply #5 on: February 03, 2010, 08:18:04 AM »

where is  the method of isSimpleType? it is not  in the Unit RtcInfo.
I Use RTC 3.32.

Logged
tintinsoft
Guest
« Reply #6 on: February 03, 2010, 08:20:47 AM »

This is my test sample,someone maybe use it!

type
  TForm6 = class(TForm)
    btnGetData: TButton;
    btn2: TButton;
    btn3: TButton;
    mmo1: TMemo;
    btn1: TButton;
    btn4: TButton;
    btn5: TButton;
    btn6: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnGetDataClick(Sender: TObject);
    procedure btn3Click(Sender: TObject);
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
    procedure btn4Click(Sender: TObject);
    procedure btn5Click(Sender: TObject);
  private
    { Private declarations }
    Rec:TRtcRecord;
    procedure Log(const s:string);
  public
    { Public declarations }
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

Function GetRandomString: String;
const
 Max_Len = 10;
var
 i: Byte;
 s: string;
begin
  s := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  s := s + '0123456789';
  Result := '';
  for i := 0 to Max_Len-1 do
   Result := Result + s[Random(Length(s)-1)+1];
end;

procedure TForm6.btnGetDataClick(Sender: TObject);
var
  i:Integer;
begin
  Rec.Clear;
  for i := 0 to 9999 do
  begin
    with Rec.NewRecord('RTC'+IntToStr(i)) do
    begin
      asLargeInt['Tick'] := GetTickCount;
      asDateTime['CreateTime'] := Now;
      asString['Value'] := GetRandomString;
    end;
  end;
end;

procedure TForm6.btn1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Length(Rec.toCode)));
end;

procedure TForm6.btn2Click(Sender: TObject);
begin
  ShowMessage(Rec.FieldName[0]);
end;

procedure TForm6.btn3Click(Sender: TObject);
var
  i,j:Integer;
  fName:string;
  Arr:TRtcArray;
  SubRec:TRtcRecord;
begin
  mmo1.Lines.BeginUpdate;
  try
    for i := 0 to Rec.FieldCount -1 do
    begin
      fName :=  Rec.FieldName;
      mmo1.Lines.Add(fName);
      if rec.isType[fName] = rtc_Array then
      begin
        Arr := Rec.asArray[fName];
        for j := 0 to arr.FieldCount -1 do
         Log('  Element '+IntToStr(j)+
                ' Field Type='+rtcTypeName(arr.isType[j])+
                '; FieldValue='+arr.asString[j]);

      end
      else if rec.isType[fName] = rtc_Record then
      begin
        SubRec := Rec.asRecord[fName];
        for j := 0 to SubRec.FieldCount -1 do
         Log('  Element '+IntToStr(j)+
                ' Field Type='+rtcTypeName(SubRec.isType[SubRec.FieldName[j]])+
                '; FieldValue='+SubRec.asString[SubRec.FieldName[j]]);
      end
      else
      begin
        Log('  FieldName='+fname+'; FieldType='+rtcTypeName(rec.isType[fname]));

      end;
    end;
  finally
    mmo1.Lines.EndUpdate;
  end;
end;

procedure TForm6.btn4Click(Sender: TObject);
var
  i:Integer;
begin
  Rec.Clear;
  for i := 0 to 9999 do
  begin
    with Rec.NewRecord(IntToStr(i)) do
    begin
      asLargeInt['Tick'] := GetTickCount;
      asDateTime['CreateTime'] := Now;
      asString['Value'] := GetRandomString;
    end;
  end;
end;

procedure TForm6.btn5Click(Sender: TObject);
begin
  ShowMessage(Rec.FieldName[0]);
end;

procedure TForm6.FormCreate(Sender: TObject);
begin
  Rec := TRtcRecord.Create;
end;

procedure TForm6.FormDestroy(Sender: TObject);
begin
  Rec.Free;
end;

procedure TForm6.Log(const s:string);
begin
  mmo1.Lines.Add(s)
end;
Logged
tintinsoft
Guest
« Reply #7 on: February 03, 2010, 08:25:20 AM »

This is the sample result,If you see you will understand Strcuture of tRtcRecord DataType.

sample1:

RTC0
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=EGPXHDQS16
RTC1
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=MMR7EEO4WD
RTC2
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=RF8SXMHBEK
RTC3
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=3AU1KR4AEF
RTC4
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=70KMDEFFAQ
RTC5
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=KNI5LS2YDJ
RTC6
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=G5O85ZXRU7
RTC7
  Element 0 Field Type=LargeInt; FieldValue=24731093
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:21:4.328
  Element 2 Field Type=String; FieldValue=84A3OBRQZV
............................

sample2:
0
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=6KERRTOMJU
1
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=RGQIC0HRZ8
2
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=D15U5RRLI3
3
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=OFJFLR8PTI
4
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=B18YOWPQXS
5
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=QWMNC7NVQI
6
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=MXFPO4R6LH
7
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=6JB5R5ZCEM
8
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=4CABS73ZJF
9
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=A4KY0DVKGA
10
  Element 0 Field Type=LargeInt; FieldValue=24951296
  Element 1 Field Type=DateTime; FieldValue=2010-2-3 15:24:44.531
  Element 2 Field Type=String; FieldValue=L3EEYA3177
..............................
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #8 on: February 03, 2010, 10:31:51 AM »

Thank you for your feedback.

I've corrected the typo in my post above, the function name I should have used was "isSimpleValue" and not "isSimpleType". The function is available in the "rtcInfo" unit. There is also "isSimpleValueType" function, which will accept a RTC Value Type (rtc_Integer, rtc_String, rtc_Record, etc) as a parameter instead of a TRtcValueObject. You might want look at the HELP for the rtcInfo unit, or simply open the unit and look at its interface section, because it offers a lot of functions which will be very useful when writing a Web Server. You can start by search for "implementation" and then go up, since there are a lot of classes in that unit and you might miss the function declarations part if you just scroll down.

Also, the "Log" function which I was using in the example above is available in the "rtcLog.pas" unit, which implements thread-safe functions for debugging and logging into local files and is very useful if you want to know what went wrong in your code and log any unexpected exceptions on your Server and/or Client.

Btw ... every field (element) inside TRtcRecord, TRtcInfo, TRtcFunctionName, TRtcArray and TRtcDataSet objects can be of any TRtcValueObject types, including TRtcRecord, TRtcInfo, etc. This means that you can create any structure you want by using only RTC Value object types. You should also take a look at the TRtcValue class, which is a container and can hold any RTC Value Object type with functions you can use to check the type and access its data.

TRtcFunctionInfo class is extending the TRtcRecord class and is used for passing a function call object, which has a name (FunctionName) and any number of parameters, each parameter having a name and being of any TRtcValueObject type.

TRtcValue class is a container which can hold an object of the TRtcValueObject type and offers easy-to-use methods for checking the type and accessing the contained value object. TRtcValue class has no type of its own and will be seen as a NULL value if nothing is stored inside it. It can also be cleared to a NULL value, destroying the contained object by using its "isNull" property ("myValue.isNull:=TRUE" will destroy any objects contained).

Best Regards,
Danijel Tkalcec
Logged
agsoft
Newbie
*
Posts: 15


« Reply #9 on: February 08, 2010, 02:24:39 AM »

I am TinTinSoft, I have bought the RTC SDK.why I cannot new topic in PRO Community?
How can delete TRTCRecrod?
if use the "TRTCRecrod.IsNull['Code'] := True",It can clear the record data,but it remain the node name.
for exmaple:

With RTCData.NewRecord('A1') do
begin
   With RTCData.NewRecord('B1') do
   begin
      AsInteger['C1'] := GetTickCount();
      AsString['Name'] := 'rtc'
   end;
 
  With RTCData.NewRecord('B2') do
   begin
      AsInteger['C1'] := GetTickCount();
      AsString['Name'] := 'rtc'
   end;
   .....

end;

With RTCData.NewRecord('A2') do
........


-------------------------------------------------------------------------
delete B1 Node: RTCData.AsRecord['A1'].isNull['B1'] := True;
loop the RTCData,show detail record:

A1
   B1                            //clear the C1,Name,but B1 NodeName remain
   B2
      C1
      Name
A2
  B1
     C1
     NAME
  B2
    C1
    NAME

...........

How can delete completely A1.B1 Node in the RtcRecord ?
 
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #10 on: February 08, 2010, 03:40:44 AM »

1) As clearly stated on the order page, PRO support is ONLY included in BRONZE, SILVER and GOLD subscriptions. BASIC subscription ONLY includes access to the latest version of the RTC SDK, but does NOT include any kind of support.

2) You can NOT remove a node by setting its value to NULL, because NULL is also a value. Nodes with a NULL value are valid nodes of type rtc_Null and will return "isNull=TRUE".

Best Regards,
Danijel Tkalcec
Logged
agsoft
Newbie
*
Posts: 15


« Reply #11 on: February 08, 2010, 06:38:09 AM »

I Mean I delete a node,i hope the fieldcount decrease 1.I test the method of kill,free...,it can raise exception.
how can you do?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #12 on: February 08, 2010, 01:52:12 PM »

Do NOT use Free or Kill on objects stored inside other objects !!! The pointer to the object will remain in the parent structure and will generate an Access Violation when the object is serialized and prepared for sending !!!

If you want to extract a field from its parent structure, use "Extract". Then you can do with it as you pleas and Free it when you no longer need it. And if you want to clear a value of an already assigned field, use "isNull[]:=TRUE".

But ... one thing you can NOT do with fields inside RTC Value objects is to completely remove any trace of their prior existence. If you assign a value to a field inside a record, unless you remove the complete record, the field name will remain in the record structure with a NULL value. You can NOT completely eliminate any trace of the field after you have assigned it a value.

This is like asking how to delete a field from a Delphi record. You can clear its value or delete the complete record if its dynamically allocated, but the structure definition will remain. And the same goes for elements inside an array or fields inside a dataset.

What I am wondering is WHY would you want to delete any trace of an element in memory after you have already assigned a value to it? If you need to do this, then something is probably wrong with your algorithm. It is either too lazily written, or you are trying to use RTC Value objects for something they were not designed for.

Best Regards,
Danijel Tkalcec
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.032 seconds with 16 queries.