Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 10 of 19 total
Thread Temporary Index
Thu, Jun 4 2009 12:02 PMPermanent Link

Eric Derrien
Hi,

I use a TStringList to generate a index in memory and I put in object the RecNo of record
But I don't arrive to set the record with the RecNo in TDataSet.GetRecord method
I do not want to create an index in the table because the table is used by more than 100 users, I need to create an temporary index only for read data in a
grid
I've put the code below

 THXTable = class(TDBIsamTable)
 private
   FOrderList: TStrings;
   FOrderPos: Integer;
   FReverseOrder: Boolean;
   FInGetRecord: Boolean;
   //
   procedure SetReverseOrder(const Value: Boolean);

 protected
   function  GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
   procedure InternalFirst; override;
   procedure InternalLast; override;

 public
   constructor Create(AOwner: TComponent); override;
   destructor  Destroy; override;

 public
   procedure CancelOrderBy;
   procedure SetOrderBy(AFieldName: string; AAscendant: Boolean=True);
   //
   property  ReverseOrder: Boolean read FReverseOrder write SetReverseOrder;
 end;

constructor THXTable.Create(AOwner: TComponent);
begin
 FOrderList    := nil;
 FReverseOrder := False;
 FInGetRecord  := False;
 //
 inherited Create(AOwner);
end;

destructor THXTable.Destroy;
begin
 inherited Destroy;
 //
 if FOrderList <> nil then
   FOrderList.Free;
end;

procedure THXTable.CancelOrderBy;
begin
 if FOrderList <> nil then
 begin
   FOrderList.Free;
   FOrderList := nil;
 end;
end;

procedure THXTable.SetOrderBy(AFieldName: string; AAscendant: Boolean);
var
 myList: TStringList;
 myField: TField;
 myCode: string;
begin
 CancelOrderBy;
 //
 myField := FindField(AFieldName);
 if myField <> nil then
 begin
   if RecordCount < 60000 then
   begin
     myList := TStringList.Create;
     DisableControls;
     try
       IndexName := '';
       First;
       while not Eof do
       begin
         case myField.DataType of
           ftSmallint, ftShortint, ftWord, ftInteger, ftLongWord :
             myCode := Format( '%08.8d', [myField.AsInteger]);
           ftDate, ftDateTime:
             myCode := FormatDateTime( 'yyyymmddhhnn', myField.AsDateTime);
           ftFloat, ftCurrency:
             myCode := Format( '%015.4f', [myField.AsCurrency]);
         else
             myCode := myField.AsString
         end;
         //
         myList.AddObject(myCode, Pointer(GetRecNo));  // RecNo

         Next;
       end;
       myList.Sort;

     finally
       FOrderList := myList;
       EnableControls;
     end;
   end;
 end;
end;

function THXTable.GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode;
 DoCheck: Boolean): TGetResult;
var
 myID: Integer;
begin
 if not FInGetRecord then
 begin
   FInGetRecord := True;
   try
     if ReverseOrder And (GetMode <> gmCurrent) then
     begin
       if GetMode = gmNext then
         GetMode := gmPrior else
         GetMode := gmNext;
     end;
     //
     if FOrderList <> nil then
     begin
       if GetMode = gmNext then
       begin
         if FOrderPos < FOrderList.Count - 1 then
           Inc(ForderPos);
       end
       else
       if GetMode = gmPrior then
       begin
         if FOrderPos > 0 then
           Dec(ForderPos);
       end;

       // HOW DO IT HERE
       SetRecNo( Integer(FOrderList.Objects[ FOrderPos ])  );
       GetMode = gmCurrent;

     end;
     //
   finally
     FInGetRecord := False;
   end;
 end;
 //
 Result := inherited GetRecord(Buffer, GetMode, DoCheck);
end;
Thu, Jun 4 2009 2:06 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Eric,

<< I use a TStringList to generate a index in memory and I put in object the
RecNo of record But I don't arrive to set the record with the RecNo in
TDataSet.GetRecord method >>

Are you trying to just set the record position and then allow the normal
GetRecord method to retrieve the record contents ?

--
Tim Young
Elevate Software
www.elevatesoft.com

Thu, Jun 4 2009 3:59 PMPermanent Link

Eric Derrien
"Tim Young [Elevate Software]" wrote:
 Are you trying to just set the record position and then allow the normal
 GetRecord method to retrieve the record contents ?

I'm try with :
 ActiveBuffer
 PrimaryIndex (Integer)

How do it : just set the record position with TDataSet because the record is not refresh in the internal buffers
Fri, Jun 5 2009 2:05 AMPermanent Link

Eric Derrien
This morning I'm try with :

in SetOrderBy : use RecordNumber of TDataCursor
   myList.AddObject(myCode, Pointer( Handle.RecordNumber ));

in GetRecord (Handle = TDataCursor)
       myRecord := Integer(FOrderList.Objects[ FOrderPos ]);
       Handle.SetCurrentRecord(myRecord);    // Handle.SetToRecordNumber(myRecord);

       Buffer  := TRecordBuffer(Handle.CurrentRecordBuffer);      // Handle.GetCurrentRecord(pAnsiChar(Buffer), False);
       GetMode := gmCurrent;

inherited GetRecord // method of TDBIsamDataSet

I don't see the error in position, perhaps I forgot something or not use the proper methods
Fri, Jun 5 2009 4:09 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Eric,

<< I'm try with :
 ActiveBuffer
 PrimaryIndex (Integer)

How do it : just set the record position with TDataSet because the record
is not refresh in the internal buffers >>

What you want is this:

function THXTable.GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode;
 DoCheck: Boolean): TGetResult;
var
 myID: Integer;
begin
 if not FInGetRecord then
 begin
   FInGetRecord := True;
   try
     if ReverseOrder And (GetMode <> gmCurrent) then
     begin
       if GetMode = gmNext then
         GetMode := gmPrior else
         GetMode := gmNext;
     end;
     //
     if FOrderList <> nil then
     begin
       if GetMode = gmNext then
       begin
         if FOrderPos < FOrderList.Count - 1 then
           Inc(ForderPos);
       end
       else
       if GetMode = gmPrior then
       begin
         if FOrderPos > 0 then
           Dec(ForderPos);
       end;

       // Just use the internal call to the engine and don't try to use the
TDBISAMDataSet.SetRecNo call

       Handle.SetToRecordNumber(Integer(FOrderList.Objects[ FOrderPos ]));
       GetMode = gmCurrent;

     end;
     //
   finally
     FInGetRecord := False;
   end;
 end;
 //
 Result := inherited GetRecord(Buffer, GetMode, DoCheck);
end;

--
Tim Young
Elevate Software
www.elevatesoft.com

Sat, Jun 6 2009 4:13 AMPermanent Link

Eric Derrien
I also tried this method, the recordings are well positioned by the buffers before call inherited GetRecord (TDBIsamTable) against then do not contain the
proper records which displays in the grid.
I'm try to set Buffer with method "Buffer  := TRecordBuffer(Handle.CurrentRecordBuffer);" before call "inherited GetRecord" but not change, same problem
Sat, Jun 6 2009 7:51 AMPermanent Link

"Robert"

"Eric Derrien" <ederrien@hotmail.com> wrote in message
news:EEA66E2C-6B92-41C6-864B-969ACF314489@news.elevatesoft.com...
> Hi,
>
> I use a TStringList to generate a index in memory and I put in object the
> RecNo of record
> But I don't arrive to set the record with the RecNo in TDataSet.GetRecord
> method
> I do not want to create an index in the table because the table is used by
> more than 100 users, I need to create an temporary index only for read
> data in a
> grid

Have you considered simply running a query and using the query to display
the data?

Robert


Mon, Jun 8 2009 1:45 AMPermanent Link

Eric Derrien
Robert" wrote:
Have you considered simply running a query and using the query to display
the data?

Yes, unfortunately this method is too slow
On a network with more than 15 users and tables that exceed the 50 000 records this solution is not viable
I'm try to sort quickly to display almost instantaneous
I use a list simply for the example, other elements are to be taken into account in sorting and filters

After tests, the solution with the TDataSet seems better geared to sortings and filters depending on the number of records or the current context (records
have already been read, only 50 records on 50 000 after filtered, ...)
The solution is there, the only remaining issue on which I get stuck is that call "TDBIsamTable.GetRecord" the buffers of TDataSet (used by grid) no longer
positioned in the order
Mon, Jun 8 2009 10:02 AMPermanent Link

"Robert"

"Eric Derrien" <ederrien@hotmail.com> wrote in message
news:8C3EF093-53D9-48D5-857F-1C989DEBC410@news.elevatesoft.com...
> Robert" wrote:
> Have you considered simply running a query and using the query to display
> the data?
>
> Yes, unfortunately this method is too slow

Yeah, I know what you mean. You might consider adding the index to the
table. Indexes cost very little in DBISAM.

Robert

Mon, Jun 8 2009 10:32 AMPermanent Link

Eric Derrien
"Robert" wrote:

Yeah, I know what you mean. You might consider adding the index to the
table. Indexes cost very little in DBISAM.

Robert

That's the irony?
Sorry but English is not my language ...

My customer use a table "documents" with 350 000 records (this table contains 69 fields and 17 indexes)
My customer use filters for view only invoice for a salesvendor, agency and amount > 10 000€ (time 1mn, 30 records, default sort = date invoice)
My customer sorted by amount and this customer does not understand that ca take 1 minute time when the results are already on the screen

So I sought a solution that allows to sort results quickly without an query restart
I myself well expressed?
Page 1 of 2Next Page »
Jump to Page:  1 2
Image