Board index » delphi » Best way to copy a record...

Best way to copy a record...

I'm building a D3 project using Interbase 5.1

One of the tables contains people's name.  I want to be able add a new
patient record & copy the information from another record.

For example:  JOHN DOE in the table and then I need to add his son JAMES
DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
state, etc,etc,etc) to JAMES DOE.

There is a primary index PERSON_ID (integer) with I will update to the
correct ID before posting.

Is there a good way to do this?

Thanks !!!

Paul
p...@rxcmpd.com.nospam
take off nospam for email

 

Re:Best way to copy a record...


There are several ways.  One is to copy the record's field values to a
variant array then copy them from the array into the new record.

--
Bill

(TeamB cannot answer questions received via email.)
(To contact me for any other reason remove nospam from my address)

Re:Best way to copy a record...


Hi Paul,

If you haven't found a simple solution to duplicating
a record;  I have a simple procedure (18 lines of code)
that duplicates a record using a BatchMove.

=======================
notes:
  T1 is Source Table
  T2 is temp Table (1 record)
  E1 is Edit  (containing new Key index)
---------------------------------------------------
procedure TForm1.DittoClick(Sender: TObject);
var  F : integer;
begin
  T2.FieldDefs := T1.FieldDefs;
  T1.IndexDefs.Update;
  T2.IndexDefs.Assign(T1.IndexDefs);
  T2.CreateTable;
  T2.Open;
  T2.Append;

  T2.Fields[0].AsInteger:=StrToInt(E1.Text);  // change Key index to E1.Text

  for F:=1 to T1.FieldCount-1 do
    T2.Fields[F].Value:=T1.Fields[F].Value;

  BM.Source:=T1;
  BM.Destination:=T2;
  BM.Mode:=batAppend;
  BM.Execute;

  BM.Source:=T2;
  BM.Destination:=T1;
  BM.Mode:=batAppendUpdate;
  BM.Execute;
  T2.Close;
end;
============================

If you would like a copy of a demo program that
uses this technique, email me.

Good luck,

Frank

Quote
Paul Klomp wrote:
> I'm building a D3 project using Interbase 5.1

> One of the tables contains people's name.  I want to be able add a new
> patient record & copy the information from another record.

> For example:  JOHN DOE in the table and then I need to add his son JAMES
> DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
> state, etc,etc,etc) to JAMES DOE.

> There is a primary index PERSON_ID (integer) with I will update to the
> correct ID before posting.

> Is there a good way to do this?

> Thanks !!!

> Paul
> p...@rxcmpd.com.nospam
> take off nospam for email

Re:Best way to copy a record...


Quote
Paul Klomp wrote:

> I'm building a D3 project using Interbase 5.1

> One of the tables contains people's name.  I want to be able add a new
> patient record & copy the information from another record.

> For example:  JOHN DOE in the table and then I need to add his son JAMES
> DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
> state, etc,etc,etc) to JAMES DOE.

> There is a primary index PERSON_ID (integer) with I will update to the
> correct ID before posting.

> Is there a good way to do this?

> Thanks !!!

> Paul
> p...@rxcmpd.com.nospam
> take off nospam for email

There is a very simple way that works well for all non-blob fields:

You just have to allocate and copy the record buffer in the BeforeInsert event and
copy it to the new record in the AfterInsert event. Here is some sample code:

Note: Regular fields and Blobs are handled differently!
(This example assumes one blob field called 'Graphic' - it is
 using the table 'biolife.db' from DBDEMOS)

procedure TForm1.Table1BeforeInsert(DataSet: TDataSet);
  begin
  GetMem(RecBuf, Table1.RecordSize);
  Table1.GetCurrentRecord(RecBuf);
  BlobBuf.Position := 0;
  TBlobField(Table1.FieldByName('Graphic')).SaveToStream(BlobBuf);
  end;

procedure TForm1.Table1AfterInsert(DataSet: TDataSet);
  begin
  Move(RecBuf^, Table1.ActiveBuffer^, Table1.RecordSize);
  FreeMem(RecBuf);
  BlobBuf.Position := 0;
  TBlobField(Table1.FieldByName('Graphic')).LoadFromStream(BlobBuf);
  end;

procedure TForm1.FormCreate(Sender: TObject);
  begin
  BlobBuf := TMemoryStream.Create;
  end;

procedure TForm1.FormDestroy(Sender: TObject);
  begin
  BlobBuf.Free;
  end;

You can also allocate the record buffer permanently, making the code
slightly more efficient.

Hope that helps,

Karl

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   Karl Waclawek
   KD Soft Inc.
 * Phone:  (905) 579-3443
 * E-Mail: wacla...@idirect.com

Re:Best way to copy a record...


Quote
Karl Waclawek wrote:

> Paul Klomp wrote:

> > I'm building a D3 project using Interbase 5.1

> > One of the tables contains people's name.  I want to be able add a new
> > patient record & copy the information from another record.

> > For example:  JOHN DOE in the table and then I need to add his son JAMES
> > DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
> > state, etc,etc,etc) to JAMES DOE.

> > There is a primary index PERSON_ID (integer) with I will update to the
> > correct ID before posting.

> > Is there a good way to do this?

> > Thanks !!!

> > Paul
> > p...@rxcmpd.com.nospam
> > take off nospam for email

> There is a very simple way that works well for all non-blob fields:

> You just have to allocate and copy the record buffer in the BeforeInsert event and
> copy it to the new record in the AfterInsert event. Here is some sample code:

> Note: Regular fields and Blobs are handled differently!
> (This example assumes one blob field called 'Graphic' - it is
>  using the table 'biolife.db' from DBDEMOS)

> procedure TForm1.Table1BeforeInsert(DataSet: TDataSet);
>   begin
>   GetMem(RecBuf, Table1.RecordSize);
>   Table1.GetCurrentRecord(RecBuf);
>   BlobBuf.Position := 0;
>   TBlobField(Table1.FieldByName('Graphic')).SaveToStream(BlobBuf);
>   end;

> procedure TForm1.Table1AfterInsert(DataSet: TDataSet);
>   begin
>   Move(RecBuf^, Table1.ActiveBuffer^, Table1.RecordSize);
>   FreeMem(RecBuf);
>   BlobBuf.Position := 0;
>   TBlobField(Table1.FieldByName('Graphic')).LoadFromStream(BlobBuf);
>   end;

> procedure TForm1.FormCreate(Sender: TObject);
>   begin
>   BlobBuf := TMemoryStream.Create;
>   end;

> procedure TForm1.FormDestroy(Sender: TObject);
>   begin
>   BlobBuf.Free;
>   end;

> You can also allocate the record buffer permanently, making the code
> slightly more efficient.

Well, I should have tested the Blob part of it.
If you don't have blob fields in your data set, this works,
at least for me. But if you have blob fields, the Move operation that
copies the old record buffer into the new one obviously also
overwrites the new blob handles and when you try to post the record
you get the "Invalid blob handle ..." exception.

Solution?
If I knew the layout of the record buffer I could simple
save the blob handles and put them back into the buffer
after the Move operation. In all generality there is no
way to do that at the TDataSet level, only at the BDE level.
So, here is another example that is tested.

Note: It only copies fields that are real, non-blob table fields,
not calculated or blob fields. The code does not check for
the ReadOnly property of the fields, for simplicity reasons.
The table used is the "biolife.db" table in the DBDEMOS
sample database.

First, we need the following declarations on the form/data module level:

    RecSize: Cardinal;
    RecBuf: PChar;
    NotesBuf, BlobBuf: TMemoryStream;
    function GetRecordSize(DataSet: TDataSet): Cardinal;

And here the rest:

function TForm1.GetRecordSize(DataSet: TDataSet): Cardinal;
  var
    Indx: Word;
  begin
  Result := 0;
  for Indx := 0 to DataSet.FieldCount - 1 do
    with DataSet, Fields[Indx] do
      if (FieldKind = fkData) and (FieldNo > 0) and not IsBlob then
        Inc(Result, DataSize);
  end;

procedure TForm1.Table1BeforeInsert(DataSet: TDataSet);
  var
    TmpRecBuf: PChar;
    Indx: Word;
  begin
  BlobBuf.Position := 0;
  TBlobField(Table1.FieldByName('Graphic')).SaveToStream(BlobBuf);
  NotesBuf.Position := 0;
  TBlobField(Table1.FieldByName('Notes')).SaveToStream(NotesBuf);
  TmpRecBuf := RecBuf;
  for Indx := 0 to Table1.FieldCount - 1 do
    with Table1, Fields[Indx] do
      if (FieldKind = fkData) and (FieldNo > 0) and not IsBlob then
        begin
        GetData(TmpRecBuf);
        Inc(TmpRecBuf, DataSize);
        end;
  end;

procedure TForm1.Table1AfterInsert(DataSet: TDataSet);
  var
    TmpRecBuf: PChar;
    Indx: Word;
  begin
  TmpRecBuf := RecBuf;
  for Indx := 0 to Table1.FieldCount - 1 do
    with Table1, Fields[Indx] do
      if (FieldKind = fkData) and (FieldNo > 0) and not IsBlob then
        begin
        SetData(TmpRecBuf);
        Inc(TmpRecBuf, DataSize);
        end;
  BlobBuf.Position := 0;
  TBlobField(Table1.FieldByName('Graphic')).LoadFromStream(BlobBuf);
  NotesBuf.Position := 0;
  TBlobField(Table1.FieldByName('Notes')).LoadFromStream(NotesBuf);
  Table1.FieldByName('Species No').Value := 99999;
  end;

procedure TForm1.FormCreate(Sender: TObject);
  begin
  Table1.Open;
  RecSize := GetRecordSize(Table1);
  GetMem(RecBuf, RecSize);
  BlobBuf := TMemoryStream.Create;
  NotesBuf := TMemoryStream.Create;
  end;

procedure TForm1.FormDestroy(Sender: TObject);
  begin
  FreeMem(RecBuf);
  BlobBuf.Free;
  NotesBuf.Free;
  end;

This works on my system, at least.
Hope it gives you some ideas.
It may be simpler to use variants, but this version of the
code is more efficient, imo.

Karl

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   Karl Waclawek
   KD Soft Inc.
 * Phone:  (905) 579-3443
 * E-Mail: wacla...@idirect.com

Re:Best way to copy a record...


I've been doing it this way... now you all got me thinking that this might
not be the way to "clone" a record... (this is performed after an Append of
a new "empty" record)...

        for i := 0 to destTable.FieldCount-1 do
          destTable.Fields[i].Assign( srcTable.Fields[i] );

destTable and srcTable address the same shared table.

Am I going to get bit by this???  It seems to work with BDE/DBase7 as well
as Halcyon xBase Datasets.

Quote
Paul Klomp wrote:
> I'm building a D3 project using Interbase 5.1

> One of the tables contains people's name.  I want to be able add a new
> patient record & copy the information from another record.

> For example:  JOHN DOE in the table and then I need to add his son JAMES
> DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
> state, etc,etc,etc) to JAMES DOE.

> There is a primary index PERSON_ID (integer) with I will update to the
> correct ID before posting.

> Is there a good way to do this?

> Thanks !!!

> Paul
> p...@rxcmpd.com.nospam
> take off nospam for email

--
Eric

P.S. To reply via email, remove "NoSpam" from my reply address

Re:Best way to copy a record...


Isn't the problem with this only if you re-structure the database file and
forget to add the TFields in your program.  Somewhere in  the Knowledgebase
there is code I saw once to use the direct BDE calls.  It wouldn't have this
shortcoming and would probably  be much faster.

I don't have a clean version of all of it.  But this is one of the
functions:

============================================================================
============
{ _GetCurrentRecord extracts the current record into a buffer
{===========================================================================
=============}
function _GetCurrentRecord(ATable : TTable; var pRecordBuf: PChar ):
boolean;
var curProp : CURProps;                 { Properties of the table }
begin
  Result := False;
  try
    { Read cursor properties }
    Check(DbiGetCursorProps( ATable.Handle, curProp));

    { Allocate memory for the record buffer }
    GetMem( pRecordBuf, curProp.iRecBufSize);

    if Assigned (pRecordBuf) then
    { 'Initialise' record buffer as per bde }
    Check(DbiInitRecord( ATable.Handle, pRecordBuf));

    { Read current record }
    Result := ATable.GetCurrentRecord( pRecordBuf );

    except
     { If an error occurs, release memory }
      if Assigned(pRecordBuf) then FreeMem( pRecordBuf,
curProp.iRecBufSize);
  end;
end;

I bet you can search on parts of this and find the rest.

Quote
Eric Himmer wrote in message <35C62EEF.1FAA...@usa.netNoSpam>...
>I've been doing it this way... now you all got me thinking that this might
>not be the way to "clone" a record... (this is performed after an Append of
>a new "empty" record)...

>        for i := 0 to destTable.FieldCount-1 do
>          destTable.Fields[i].Assign( srcTable.Fields[i] );

>destTable and srcTable address the same shared table.

>Am I going to get bit by this???  It seems to work with BDE/DBase7 as well
>as Halcyon xBase Datasets.

>Paul Klomp wrote:

>> I'm building a D3 project using Interbase 5.1

>> One of the tables contains people's name.  I want to be able add a new
>> patient record & copy the information from another record.

>> For example:  JOHN DOE in the table and then I need to add his son JAMES
>> DOE.  I want to be able to copy ALL of JOHN DOE's information (address,
>> state, etc,etc,etc) to JAMES DOE.

>> There is a primary index PERSON_ID (integer) with I will update to the
>> correct ID before posting.

>> Is there a good way to do this?

>> Thanks !!!

>> Paul
>> p...@rxcmpd.com.nospam
>> take off nospam for email

>--
>Eric

>P.S. To reply via email, remove "NoSpam" from my reply address

Other Threads