Client Data Set in Detail2

  • Upload
    yc1965

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

  • 8/14/2019 Client Data Set in Detail2

    1/6

    Defining a ClientDataSet's Structure UsingFieldDefs

    By: Cary Jensen

    Abstract: When creating a ClientDataSet's memory store on-the-fly, you must explicitly define the

    structure of your table. This article shows you how to do it at both runtime and design-time using

    FieldDefs.

    The ClientDataSet is an in-memory data store that lets you to view, edit, and navigate data. Because

    these operations are performed on data held in memory, they tend to be performed very quickly.

    This is the second article in a series designed to detail the use of the ClientDatSet. In the last

    installment, I provided you with a basic overview of ClientDataSet, with particular attention paid to

    how a ClientDataSet gets its data from a DataSetProvider. You use a ClientDataSet with a

    DataSetProvider when you obtain your data through a remote database management system (RDBMS)

    or a local database engine, such as the Borland Database Engine (BDE). Instead of using a

    DataSetProvider, it is possible to load and save the data held by a ClientDataSet from the local file

    system. Borland calls this mechanism MyBase.

    As you learned in the preceding article in this series, a ClientDataSet loaded through a

    DataSetProvider get its metadata, the data that defines the fields of the dataset (commonly referred to

    as a table's structure), through the DataSetProvider. This metadata is produced by the

    DataSetProvider, based on the DataSet to which it points.

    When a ClientDataSet gets its data from a local file using MyBase, the metadata is read from this file.

    However, neither mechanism is available when you create the in-memory dataset on-the-fly, at

    runtime. In these situations, it is necessary for you to explicitly define the structure of the

    ClientDataSet. Defining this metadata can be done either at design-time or at runtime. Once the

    metadata is defined, you create the in-memory dataset by calling the ClientDataSet's CreateDataSet

    method, or by using the ClientDataSet's component editor in the designer.

    There are two ways to define the metadata of a ClientDataset. You can use the FieldDefs property of

    the ClientDataSet, or you can create TFields and associate them with the ClientDataSet. Creating the

    metadata definitions using FieldDefs is the most common. However, FieldDefs does not permit you to

    create virtual fields, such as calculated or aggregate fields. Similarly, using FieldDefs does not allow

    you to easily create nested datasets. Nested datasets represent one-to-many (sometimes called

    master-detail or parent-child) associations in your data. In this article you will learn how to use

    FieldDefs. The next article in this series will discuss the use of TFields to define the structure of aClientDataSet.

    Defining a Table's Structure Using FieldDefs

    You can configure FieldDefs either at design time or at runtime. To define the structure of a client

    dataset at design time, you use the FieldDefs collection editor to create individual FieldDef instances.

    You then use the Object Inspector to configure each FieldDef, defining the field name, data type, size,

    or precision, among other options. At runtime, you define your FieldDef objects by calling the

    FieldDefs AddFieldDef or Add methods. This section begins by demonstrating how to create your

    ClientDataSet's structure at design-time. Defining the table structure at runtime is shown later in this

    article.

    Creating FieldDefs at Design-time

    You create FieldDefs at design-time using the FieldDefs collection editor. To display this collection

    editor, select the FieldDefs property of a ClientDataSet in the Object Inspector and click the displayed

    ellipsis button. The FieldDefs collection editor is shown in the following figure.

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959

    6 20.11.2008 17:18

  • 8/14/2019 Client Data Set in Detail2

    2/6

    Using the FieldDefs collection editor, click the Add New button (or press Ins) once for each field that

    you want to include in your ClientDataSet. Each click of the Add New button (or press of Ins) will

    create a new FieldDef instance, which will be displayed in the collection editor. For example, if you add

    five new FieldDefs to the FieldDefs collection editor, it will look something like that shown in the

    following figure.

    You must configure each FieldDef that is added to the FieldDefs collection editor before the dataset can

    be created. To configure a FieldDef, select the FieldDef you want to configure in the collection editor or

    the Object TreeView, and then use the Object Inspector to set its properties. The following is how the

    Object Inspector looks when a FieldDef is selected. (Notice that the Attributes property has been

    expanded to display its subproperties.)

    At a minimum, you must set the DataType property of each FieldDef. You will also want to set the

    Name property. The Name property defines the name of the corresponding field that will be created.

    Other properties you will often set include the Size property, which you define for String, BCD (binary

    coded decimal), byte, and VarByte fields, and the precision property for BCD fields. Similarly, if a

    particular field requires a value before the record to which it is associated can be posted, set the

    faRequired subproperty of the Attributes property to True. For information on the other properties of

    the TFieldDef class, see the online help.

    After setting the necessary properties of each FieldDef, you can create the ClientDataSet. This can be

    done either at design-time or runtime. To create the ClientDataSet at design-time, right-click the

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959

    6 20.11.2008 17:18

  • 8/14/2019 Client Data Set in Detail2

    3/6

    ClientDataSet and select Create DataSet, as shown in the following figure.

    Creating the dataset at design-time creates an in-memory table, but does not actually create a

    physical file on disk. You save a physical file by right-clicking the ClientDataSet and selecting one of

    the save options, such as Save to MyBase Xml table or Save to binary MyBase file.

    If you create your physical file at design-time, you will then likely need to deploy that file, along with

    any other required files. As a result, many ClientDataSet users create the ClientDataSet at runtime.

    As mentioned earlier in this article, this task is performed by calling the ClientDataSet's

    CreateDataSet method. For example, consider the following event handler, which might be associated

    with the OnCreate event handler of the form to which it is associated.

    procedure TForm1.FormCreate(Sender: TObject);const

    DataFile = 'mydata.xml';

    begin

    ClientDataSet1.FileName := ExtractFilePath(Application.ExeName) + DataFile;

    if FileExists(ClientDataSet1.FileName) then

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959

    6 20.11.2008 17:18

  • 8/14/2019 Client Data Set in Detail2

    4/6

    ClientDataSet1.Open

    else

    ClientDataSet1.CreateDataSet;

    end;

    This code begins by defining the FileName property of the ClientDataSet, pointing to a file named

    mydata.xml in the application directory. Next, it tests to see if this file already exists. If it does, it

    opens the ClientDataSet, loading the specified file's metadata and data into memory. If the file does

    not exist, it is created through a call to CreateDataSet. When CreateDataSet is called, the in-memory

    structure is created based on the FieldDefs property of the ClientDataSet.

    Creating FieldDefs at Runtime

    Being able to create FieldDefs at design-time is an important feature, in that the Object Inspector

    provides you with assistance in defining the various properties of each FieldDef you add. However,

    there may be times when you do not know the structure of the dataset that you need until runtime. In

    those cases, you must define the FieldDefs property at runtime.

    As mentioned earlier in this article, there are two methods that you can use to configure the FieldDefs

    property at runtime. The easiest technique is to use the Add method of the TFieldDefs class. The

    following is the syntax of Add:

    procedure Add(const Name: String; DataType: TFieldType;

    Size: Integer = 0; Required: Boolean = False);

    This method has two required parameters and two optional parameters. The first parameter is the

    name of the FieldDef and the second is its type. If you need to set the Size property, as is the case

    with fields of type ftString and ftBCD, set the Size property to the size of the field. For required fields,

    set the fourth property to a Boolean True.

    The following code sample creates an in-memory table with five fields.

    procedure TForm1.FormCreate(Sender: TObject);

    const

    DataFile = 'mydata.xml';begin

    ClientDataSet2.FileName :=

    ExtractFilePath(Application.ExeName) + DataFile;

    if FileExists(ClientDataSet2.FileName) then

    ClientDataSet2.Open

    else

    begin

    with ClientDataSet2.FieldDefs do

    begin

    Clear;

    Add('ID',ftInteger, 0, True);

    Add('First Name',ftString, 20);

    Add('Last Name',ftString, 25);

    Add('Date of Birth',ftDate);

    Add('Active',ftBoolean); end; //with ClientDataSet2.FieldDefs

    ClientDataSet2.CreateDataSet;

    end; //else

    end;

    Like the previous code listing, this code begins by defining the name of the data file, and then testing

    whether or not it already exists. When it does not exist, the Add method of the FieldDefs property is

    used to define the table structure, after which the in-memory dataset is created using the

    CreateDataSet method.

    If you consider how the Object Inspector looks when an individual FieldDef is selected in the FieldDefs

    collection editor, you will notice that the Add method is rather limited. Specifically, using the Add

    method you cannot create hidden fields, readonly fields, or BCD fields where you define precision. Forthese more complicated types of FieldDef definitions, you will need to use the AddFieldDef method of

    the FieldDefs property. The following is the syntax of AddFieldDef:

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959

    6 20.11.2008 17:18

  • 8/14/2019 Client Data Set in Detail2

    5/6

    function AddFieldDef: TFieldDef;

    As you can see from this syntax, this method returns a TFieldDef instance. Set the properties of this

    instance to configure the FieldDef. The following code sample shows you how to do this.

    procedure TForm1.FormCreate(Sender: TObject);

    const

    DataFile = 'mydata.xml';

    beginClientDataSet2.FileName :=

    ExtractFilePath(Application.ExeName) + DataFile;

    if FileExists(ClientDataSet2.FileName) then

    ClientDataSet2.Open

    else

    begin

    with ClientDataSet2.FieldDefs do

    begin

    Clear;

    with AddFieldDef do

    begin

    Name := 'ID';

    DataType := ftInteger;

    end; //with AddFieldDef do

    with AddFieldDef do begin

    Name := 'First Name';

    DataType := ftString;

    Size := 20;

    end; //with AddFieldDef do

    with AddFieldDef do

    begin

    Name := 'Last Name';

    DataType := ftString;

    Size := 25;

    end; //with AddFieldDef do

    with AddFieldDef do

    begin

    Name := 'Date of Birth';DataType := ftDate;

    end; //with AddFieldDef do

    with AddFieldDef do

    begin

    Name := 'Active';

    DataType := ftBoolean;

    end; //with AddFieldDef do

    end; //with ClientDataSet2.FieldDefs

    ClientDataSet2.CreateDataSet;

    end; //else

    end;

    Saving Data

    If you have assigned a file name to the FileName property of a ClientDataSet whose in-memory table

    you create using CreateDataSet, and post at least one new record to the dataset, a physical file will be

    written to disk when you close or destroy the ClientDataSet. This happens automatically. Alternative,

    you can call the SaveToFile method of the ClientDataSet to explicitly save your data to a physical file.

    The following is the syntax of SaveToFile

    procedure SaveToFile(const FileName: string = '';

    Format TDataPacketFormat=dfBinary);

    As you can see, both of the parameters of this method are optional. If you omit the first parameter,

    the ClientDataSet saves to a file whose name is assigned to the FileName property. If you omit the

    second parameter, the type of file that is written to disk will depend on the file extension of the file towhich you are saving the data. If the extension is XML, an XML MyBase file is created. Otherwise, a

    binary MyBase file is written. You can override this behavior by specifying the type of file you want to

    write. If you pass dfBinary as the second parameter, a binary MyBase file is created. To create an XML

    MyBase file when the file extension of the file name is not XML, use dfXML.

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959

    6 20.11.2008 17:18

  • 8/14/2019 Client Data Set in Detail2

    6/6

    On more than one occasion I have noticed that the XML MyBase file is not written to disk correctly if

    you do not explicitly call SaveToFile. Therefore, even though a ClientDataSet can save its data

    automatically, I make a habit of explicitly calling SaveToFile before closing or destroying a

    ClientDataSet.

    An Example

    An example application that demonstrates the use of the FieldDefs methods AddFieldDefs and Add can

    be downloaded from Code Central. The following is how the main form of this application looks after

    File | Create or Load is selected from the main menu.

    About the Author

    Cary Jensen is President of Jensen Data Systems, Inc., a Texas-based training and consulting companythat won the 2002 Delphi Informant Magazine Readers Choice award for Best Training. He is the

    author and presenter for Delphi Developer Days (www.DelphiDeveloperDays.com), an information-

    packed Delphi seminar series that tours North America and Europe. Cary is also an award-winning,

    best-selling co-author of eighteen books, including Building Kylix Applications (2001,

    Osborne/McGraw-Hill), Oracle JDeveloper (1999, Oracle Press), JBuilder Essentials (1998,

    Osborne/McGraw-Hill), and Delphi In Depth (1996, Osborne/McGraw-Hill). For information about

    onsite training and consulting you can contact Cary at [email protected], or visit his

    Web site at www.JensenDataSystems.com.

    Click here for a listing of upcoming seminars, workshops, and conferences where Cary Jensen is

    presenting.

    Copyright ) 2002 Cary Jensen, Jensen Data Systems, Inc.

    ALL RIGHTS RESERVED. NO PART OF THIS DOCUMENT CAN BE COPIED IN ANY FORM WITHOUT THE

    EXPRESS, WRITTEN CONSENT OF THE AUTHOR.

    Published on: 8/1/2002 12:04:54 PM

    Server Response from: BDN9A

    Copyright 1994 - 2008 Embarcadero Technologies, Inc. All rights reserved.

    ning a ClientDataSet's Structure Using FieldDefs http://dn.codegear.com/print/28959