或SetRange函数时给出字段的近似值,程序示例如下: Table1.SetRangeStart;Table1[''''LastName''''] := ''''Smith''''; Table1.SetRangeEnd;Table1[''''LastName''''] := ''''Zzzzzz''''; Table1.ApplyRange; 下列代码将使所有LastName字段的值大于“Sm”并且FirstName字段的值大于“J”的记录被选择。 Table1.SetRangeStart;Table1[''''LastName''''] := ''''Sm''''; Table1[''''FirstName''''] := ''''J''''; Table1.SetRangeEnd;Table1[''''LastName''''] := ''''Zzzzzz''''; Table1.ApplyRange; 8.4.6 应用和取消范围 调用SetRangeStart、SetRangeEnd或SetRange只是设置了范围的起点和终点,但还没有真正地使范围有效,还需要调用ApplyRange函数。 调用了ApplyRange 后,应用程序只能工作于一定范围内的记录。如果以后又想工作于所有的记录,可以调用CancelRange。不过,调用了CancelRange后,原先设置的起点和终点仍然保留,因为下次还可能要用到它们。起点和终点的设置将一直保留,除非设置了新的起点和终点。 8.4.7 修改范围的起点和终点 要修改原有的起点和终点,可以调用EditRangeStart和EditRangeEnd函数。调用EditRangeStart和EditRangeEnd将使数据集处于dsSetKey状态。 一旦调用EditRangeStart后,以后对字段的赋值就认为是范围的起点。对于Paradox 和dBASE来说,调用EditRangeStart后,只能对关键字段赋值。 一旦调用EditRangeEnd后,以后对字段的赋值就认为是范围的终点。对于Paradox 和dBASE来说,调用EditRangeEnd后,只能对关键字段赋值。 8.5 对表格整体的操作 下面介绍几个对表格整体的操作,包括删除表格中的所有记录、删除表格、给表格换名、创建新的表格、两个表格之间保持同步。 8.5.1 删除表格中的所有记录 要删除表格中的所有记录,可以调用EmptyTable函数。对于SQL表来说,必须拥有删除记录的权限。用EmptyTable删除的记录是不能恢复的。 在调用EmptyTable之前,必须先设置DatabaseName、TableName和TableType等属性,如果表处于打开状态,必须是以独占方式打开的。程序示例如下: Procedure TForm1.Button1Click(Sender: TObject); Begin With Table1 Do Begin Active := False; DatabaseName := ''''Delphi_Demos''''; TableName := ''''CustInfo''''; TableType := ttParadox; EmptyTable; End; End; 8.5.2 删除一个表格 在设计期,要删除一个表格,可以用鼠标右键单击TTable构件,在弹出的菜单中选择“Delete Table”命令。当然,必须事先设置了DatabaseName属性和TableName属性,弹出的菜单中才会有“Delete Table”命令。 在运行期,要删除一个表格,可以调用DeleteTable。注意:用DeleteTable删除的表格是不可恢复的。在调用DeleteTable函数之前,必须设置DatabaseName、TableName和TableType属性,并且表格必须处于关闭状态。程序示例如下: With Table1 Do Begin Active := False; DatabaseName := ''''DBDEMOS''''; TableName := ''''Customer''''; TableType := ttParadox; DeleteTable; End; 8.5.3 给表格换名 在设计期,要给一个Paradox或dBASE表换名,可以用鼠标右键单击TTable构件,在弹出的菜单中选择“Rename Table”命令。 在运行期,要给一个Paradox或dBASE表换名,可以调用RenameTable函数,例如: Customer.RenameTable(''''CustInfo''''); 8.5.4 创建表格 既可以在设计期也可以在运行期创建表格。通过“Create Table”命令(设计期)或CreateTable函数(运行期),无须具备SQL的知识就能创建一个表格。不过,必须对数据集构件的有关属性、方法和事件比较熟悉,尤其是对TTable。 下面是创建一个表格的一般步骤: 第一步是设置DatabaseName属性指定要把表格放到哪个数据库中。 第二步是设置TableType属性指定表格的类型,如果是Paradox、dBASE或ASCII文本,就把TableType属性设为ttParadox、ttDBase或ttASCII。如果是其他类型,就把TableType属性设为ttDefault。 第三步是设置TableName属性指定表格的名称。如果TableType属性设为ttParadox或ttDBase,您不必给出扩展名。 第四步是建立字段定义。在设计期,您可以在对象观察器中单击FieldDefs属性边上的省略号按钮,Delphi 4将打开一个如图8.2所示的编辑器: 图8.2 建立字段定义 单击工具栏上的按钮可以创建一个新的字段,单击按钮可以删除一个字段,单击按钮可以把字段的顺序上移,单击按钮可以把字段的顺序下移。 选择其中一个字段,就可以在对象观察器中设置字段(TFieldDef对象)的定义。 在运行期,可以调用TFieldDefs的Add函数创建一个字段。 第五步是建立索引定义(可选)。在设计期,您可以在对象观察器中单击IndexDefs属性边上的省略号按钮,Delphi 4将打开一个如图8.3所示的编辑器: 图8.3 建立索引定义 单击工具栏上的按钮可以创建一个新的索引,单击按钮可以删除一个索引,单击按钮可以把索引的顺序上移,单击按钮可以把索引的顺序下移。 选择其中一个字段,就可以在对象观察器中设置索引(TIndexDef对象)的定义。 在运行期,可以调用TIndexDefs的Add函数创建一个新的索引。 注意:在设计期,可以借用一个已有的表格中的字段定义和索引定义。首先要设置DatabaseName属性和TableName属性指定一个已有的表格,然后在TTable构件上单击鼠标右键,在弹出的菜单中选择“Update Table Definition”命令,此命令将使这个表格中的字段定义和索引定义读到FieldDefs属性和IndexDefs属性中。接着,按第一步和第二步设置DatabaseName属性和TableName属性。 第六步是创建这个表格。在设计期,可以用鼠标右键单击TTable构件,在弹出的菜单中选择“Create Table”命令。在运行期,可以调用CreateTable函数。 注意:如果新建的表格与一个已有的表格重名,已有的表格将被覆盖,并且无法恢复。 下面的代码演示了怎样在运行期动态地创建一个表格: var NewTable: TTable; NewIndexOptions: TIndexOptions; TableFound: Boolean; Begin NewTable := TTable.Create; NewIndexOptions := [ixPrimary, ixUnique]; With NewTable Do Begin Active := False; DatabaseName := ''''DBDEMOS''''; TableName := Edit1.Text; TableType := ttDefault; FieldDefs.Clear; FieldDefs.Add(Edit2.Text, ftInteger, 0, False); FieldDefs.Add(Edit3.Text, ftInteger, 0, False); IndexDefs.Clear; IndexDefs.Add(''''PrimaryIndex? Edit2.Text, NewIndexOptions); End; TableFound := FindTable(Edit1.Text); If TableFound = True then If MessageDlg(''''Overwrite existing table '''' + Edit1.Text + ''''?'''', mtConfirmation,mbYesNo, 0) = mrYes then TableFound := False; If not TableFound then CreateTable; End; 8.5.5 两个表格之间保持同步 多个TTable构件可以指向同一个表格,即它们的DatabaseName属性和TableName属性相同。每个TTable构件所连接的TDataSource构件可以不同,也就是说,它们完全可以独立地工作,在不同的TTable 构件中,当前记录的位置是不同的。例如,在Table1中,第2条记录是当前记录,而在Table2中,第3条记录是当前记录。 不过,可以调用GotoCurrent函数使多个TTable构件保持同步。例如,CustomerTableOne中第2条记录是当前记录,而在CustomerTableTwo中,第3条记录是当前记录。可以这样调用GotoCurrent: CustomerTableOne.GotoCurrent(CustomerTableTwo); 如果要同步的两个TTable构件不在同一个数据模块或窗体内,可以这样写: CustomerTableOne.GotoCurrent(Form2.CustomerTableTwo); 8.6 Master/Detail关系 TTable构件的MasterSource属性和MasterFields属性可以用来建立一对多的Master/Detail关系。 这两个属性都可用于Detail表。其中,MasterSource属性用于指定一个TDataSource构件,该构件的DataSet属性指定了Master表。 MasterFields属性用于指定一个或几个字段,这些字段用于连接Master表和Detail表。如果有多个字段的话,彼此之间要用分号隔开,例如: Table1.MasterFields := ''''OrderNo;ItemNo''''; 下面我们举例说明建立Master/Detail关系的一般步骤。假设Master表叫CustomersTable,Detail表叫OrdersTable。 第一步,把两个TTable构件和两个TDataSource构件放到窗体上。 第二步,把第一个TTable构件的DatabaseName属性设为DBDEMOS,把TableName属性设为CUSTOMER,把Name属性设为CustomersTable。 第三步,把第二个TTable构件的DatabaseName属性设为DBDEMOS,把TableName属性设为ORDERS,把Name属性设为OrdersTable。 第四步,把第一个TDataSource构件的Name属性设为CustSource,把DataSet属性设为CustomersTable。 第五步,把第二个TDataSource构件的Name属性设为OrdersSource,把DataSet属性设为OrdersTable。 第六步,把两个TDBGrid构件放到窗体上,把其中第一个TDBGrid构件的DataSource属性设为CustSource,把第二个TDBGrid构件的DataSource属性设为OrdersSource。 第七步,把OrdersTable的MasterSource属性设为CustSource,这就把CUSTOMER表与ORDERS表连接起来。 第八步,单击OrdersTable的MasterFields属性边上的省略号按钮打开“FieldLink Designer”对话框,在“Available Indexes”框内选择CustNo,然后在“DetailFields”框和“Master Fields”框都选择CustNo,单击“Add”按钮。 第九步,把CustomersTable和OrdersTable的Active属性设为True。 第十步,编译和运行这个程序。您将发现,在第一个栅格中浏览CUSTOMER表时,第二个栅格中的ORDERS表将显示当前客户的所有订单。 8.7 嵌 套 表 Delphi 4用TNestedTable构件来访问嵌套表中的数据,TNestedTable是从TBDEDataSet继承下来的。下面是访问嵌套表的一般步骤: 第一步,把一个数据集构件如TTable、TQuery放到窗体或数据模块上,这个数据集中必须包含有TDataSetField或TReferenceField类型的字段。 第二步,把一个TNestedTable构件放到窗体或数据模块上,设置它的DataSetField属性指定要访问的TDataSetField或TReferenceField类型的字段,可以从下拉列表中选择。 第三步,把一个TDataSource构件放到窗体或数据模块上,设置它的DataSet属性指定TNestedTable构件。 第四步,把一个数据控件如TDBGrid构件放到窗体或数据模块上,设置它的DataSource属性指定TDataSource构件。 第五步,在设计期或运行期把TNestedTable构件的Active属性设为True。 8.8 从另一个表格中引入数据 TTable构件的BatchMove函数能够从其他表中引入数据,包括复制、添加、修改或删除记录,并返回被操作的记录数。 BatchMove函数需要传递两个参数,一个是源数据集的名称,另一个是操作方式。BatchMove函数支持以下操作方式: .batAppend把源表中的所有记录复制到目标表的末尾; .batUpdate用源表中的记录更新目标表中的记录; .batAppendUpdate把源表中不存在于目标表中的记录添加在目标表的末尾; .batDelete删除源表在目标表中重复的记录; .batCopy把源表复制到目标表。 下面的代码用Customer表中的记录更新当前表中的记录: Table1.BatchMove(''''CUSTOMER.DB'''', batUpdate); 与TBatchMove构件相比,BatchMove函数的功能比较简单。如果要移动很多的记录,最好选用TBatchMove构件。 8.9 使用TBatchMove TBatchMove构件封装了一部分BDE的功能,能够从另一个数据集中引入数据。TBatchMove构件经常用于从服务器下载数据或者把本地的数据上载到服务器。 TBatchMove构件能够自动建立一个新的表,并映射源数据集中的字段名称和类型。 8.9.1 使用TBatchMove构件的一般步骤 第一步,把一个TTable构件或TQuery构件放到窗体或数据模块上作为源数据集。 第二步,把另一个TTable构件放到窗体或数据模块上作为目标数据集。 第三步,把一个TBatchMove 构件放到数据模块上,设置它的Source属性指定源数据集,设置它的Destination属性指定目标数据集。 第四步,设置Mode属性指定操作方式,可以设为batAppend、batUpdate、batAppendUpdate、batCopy、batDelete等。 第五步(可选),设置ProblemTableName属性指定一个表的名字,执行批量移动操作时有问题的记录将放到这个表中。设置KeyViolTableName属性指定一个表的名字,更新一个Paradox表时违反主索引定义的记录将放到这个表中。设置ChangedTableName 属性指定一个表的名字,执行批量移动操作时目标表中变动的记录将放到这个表中。 第六步(可选),设置Mappings属性指定字段的映射方式。 第七步,调用Execute执行批量移动操作。 8.9.2 指定操作方式 TBatchMove构件的Mode属性用于指定操作方式: .batAppend把源表中的所有记录复制到目标表的末尾; .batUpdate用源表中的记录更新目标表中的记录; .batAppendUpdate把源表中不存在于目标表中的记录添加在目标表的末尾; .batDelete删除源表在目标表中重复的记录; .batCopy把源表复制到目标表。 对于batAppend方式来说,目标数据集必须是已存在的。如果需要的话,BDE会自动进行数据类型的转换,不过,转换并不总是能成功的。对于batUpdate方式来说,目标数据集必须是已存在的,并且必须已建立索引。TBatchMove构件根据关键字段用源数据集中的记录更新目标数据集中匹配的记录。在更新过程中,BDE会尽可能地转换数据类型。 对于batAppendUpdate方式来说,目标数据集必须是已存在的,并且必须已建立索引。TBatchMove构件根据关键字段用源数据集中的记录更新目标数据集中匹配的记录,如果没有找到匹配的记录,TBatchMove构件就把记录添加在源数据集的末尾。 对于batCopy方式来说,目标数据集最好是不存在的,如果已经存在,目标数据集中的记录会被源数据集中的记录覆盖。如果源数据集和目标数据集的结构不同,例如,一个是Paradox,另一个是InterBase,BDE会尽可能地转换。不过,TBatchMove构件不会复制源数据集的索引、纠错规则、存储过程。 对于batDelete方式来说,目标数据集必须是已存在的,并且必须已建立索引。TBatchMove构件根据关键字段删除目标数据集中重复的记录, 8.9.3 映射字段类型 默认情况下,在源数据集和目标数据集之间批量移动记录时是以字段的位置匹配的,也就是说,源数据集中的第一个字段到目标数据集中仍然是第一个字段,依次类推。如果不希望按字段的位置匹配,而希望按字段的名称匹配,就要设置Mappings属性。 Mappings属性是一个字符串列表。假设源数据集中有一个字段叫SourceColName,希望它在目标数据集中匹配DestColName字段,Mapping属性中应加入这么一行: DestColName = SourceColName 程序示例如下: Procedure TForm1.Button1Click(Sender: TObject); var Maps: TStringList; Begin With Maps Do Begin Clear;Add(''''CustNo=CustomerNum''''); Add(''''SSN''''); End; BatchMove1.Mappings := Maps; End; 如果等号两边的字段的数据类型不同,Delphi 4会尽可能地转换,但可能会丢失数据或精度。假设一个字段是CHAR(10),如果试图转换为CHAR(5),后5个字符将被截掉。 8.9.4 执行批量移动操作 调用Execute函数将执行批量移动操作。例如,假设BatchMoveAdd是TBatchMove构件的名称,要执行批量移动操作,可以这样写: BatchMoveAdd.Execute; 实际上,在设计期也可以执行批量移动操作,方法是:在TBatchMove 构件上单击鼠标右键,在弹出的菜单中选择“Execute”命令。 调用了Execute后,可以访问MovedCount属性,查看实际移动了多少条记录。 RecordCount属性用于限制每次批量移动的记录数。如果RecordCount属性设为0,表示没有限制。 8.9.5 处理错误 在进行批量移动操作的过程中,有可能发生两种类型的错误,一是数据类型转换错误,还有一种是违反数据完整性。 如果AbortOnProblem属性设为True,只要遇到一个数据类型转换错误就会停止批量移动操作。如果AbortOnProblem属性设为False,即使遇到数据类型转换错误也不会停止批量移动操作。可以在ProblemTableName属性指定的表中找到这些有错误的记录。 ProblemCount属性返回有错误的记录数。如果AbortOnProblem属性设为True,ProblemCount属性最多返回1,因为一旦遇到一个错误,操作就停止了。 AbortOnKeyViol属性类似于AbortOnProblem属性,如果AbortOnKeyViol属性设为True,只要遇到一个违反数据完整性的错误就会停止批量移动操作。 可以设置ChangedTableName属性指定一个表的名称,让TBatchMove构件把目标数据集中所有变化的记录写到这个表中。 可以设置KeyViolTableName属性指定一个表的名称,让TBatchMove构件把上一页 [1] [2] [3] 下一页 |