delphi xe 之路(20)clientdataset的详细介绍02
介绍 详细 20 02 Delphi xe
2023-09-14 08:59:39 时间
可能与前面的笔记有重复的地方
ClientDataSet组件支持很多特性,其中一些与三级结构有关,而且还可以用在其他环境中。该组件说明了一个数据库完全映象在内存 中,这使得可以进行动态的操作,如建立一个索引,其他数据集合通常不支持该特性。例如,为了对查询分类,我们通常是重新执行它。 为了索引一个局部表格,需要定义索引。只有ADO数据集合有一些与ClientDataSet一样的动态索引功能。
索引并不是ClientDataSet提供的全部功能。当我们拥有了索引之后,可以基于它定义组,可能是多级别的分组。对于确定一个记录在 组中的位置(头、尾或中间位置),甚至有专门的支持。在组或整个数据表格中,我们可以定义总计;也就是说,可以动态计算整个表格 或当前组中一列的总和或平均值。数据不需要发送给物理服务器,因为这些总计操作发生在内存中。我们甚至可以定义新的总计字段,可 以直接与数据敏感控件相连。
注意,所有这些特性不但可以用与MIDAS应用程序,还可以用与客户机/服务器,甚至是局部瘦应用程序。事实上,ClientDataSet组件 可以从远程MIDAS连接、局部数据集合(建立起数据的快照)、或局部文件(就象在公文包模式中一样,但使用的只是在客户机数据集合中 定义的整个表格)中获得起数据。
这是另一个需要研究的领域,所以将向读者演示两个范例来突出关键特性。这些范例没有基于MIDAS,而是基于局部表格。
1、定义抽象的数据的数据类型
VCL数据库支持的一个有趣的特性是,当我们基于局部文件使用ClientDataSet时,可以定义抽象的数据类型。只需在窗体上放置一个 ClientDataSet组件,为FieldDefs属性激活编辑器,添加两个字段,并为他们的DataType属性选择ftADT值。现在,移到 ChildDefs属性, 并定义子字段,下面是AdtDemo范例的字段定义:
FieldDefs = /SPAN
item
Name = ID
DataType = ftInteger
end
item
name = Name
ChildDefs = /SPAN
item
name = LastName
DataType = ftString
size = 20
end
item
name = FirstName
datatype = ftString
size = 20
end
datatype = ftADT
size = 2
end
在此,只需为ClientDataSet的FileName属性输入一个名称,用鼠标右键单击组件,并选择Create Table命令即可;我们准备编译并运 行应用程序(在向它连接数据敏感组件之后)。数据会自动从提供的文件中读取,关闭程序时会将变化保存在文件中。
如果使用DBGrid查看结果数据集合,它允许我们展开或压缩ADT字段的子字段。我们可以通过定义字段的OnGetText事件提供它的压缩 值(在 Delphi4 中有一个缺省值,但Delphi5中没有):
procedure TForm1.ClientDataSet1NameGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
Text:=ClientDataSet1NameFirstName.AsString+ +
ClientDataSet1NameLastName.AsString;
end;
2、动态索引
一旦ClientDataSet上有了数据,数据就已全部处于内存中了。当我们将组件基于局部文件中时(如在AdtDemo范例中),在程序启动 时整个文件就被装载到了内存总。这与从Paradox数据表格中装载数据(BDE只装载正访问的字段)不同。
将整个表格装在内存中的优点是,我们可以快速地对它进行分类。使用ClientDataSet组件,我们可以通过赋给IndexFieldNames属性 相应的字段名来实现分类。在AdtDemo(以及很多程序)中,该索引变动会在单击DBGrid控件的标题(触发OnTitleClick事件)时执行:
procedure TForm1.DBGrid1TitleClick(Column:TColumn);
begin
if Column.Field.FullName = Name then
ClientDataSet1.IndexFieldNames := Name.LastName
else
ClientDataSet1.IndexFieldNames := Column.Field.FullName;
end;
由于ADT定义,程序使用了字段的FullName属性(而不是FieldName属性)。事实上,对于子字段来说,索引应该基于 Name.LastName, 而不是LastName。而且ADT字段不能自己被索引,所以如果选择它,程序会使用LastName子字段作为索引。这些索引不是持久性的;它们没 有保存在文件中,而只是在内存中应用于数据。
技巧:ClientDataSet可以拥有基于计算字段的索引,特别是内部计算字段,这种字段类型只能用于该数据集合。
3、分组
一旦为ClientDataSet定义了一个索引,就可以通过该索引对数据进行分组了。实际上,一组被定义为连续记录的一个列表(根据索引 ),记录中被索引的字段的值不会改变。例如,如果有一个基于国家的索引,带有该国家的所有地址都将归为一组。
cdsCalcs范例有一个ClientDataSet组件,它同样从DBDEMOS数据库的Country表格中读取其数据。该操作可以在设计时,使用 ClientDataSet组件快捷菜单的Assign Local Data命令来执行。为了在运行时读取数据,获得一个更新的快照,可以向窗体添加一个 DataSetProvider组件,如下连接三个组件:
Object Table :TTable
active = true
databasename = dbdemos
tablename = country.db
end
object datasetprovider1: TDataSetProvider
dataset = table1
end
object clientdataset1: tclientdataset
providername = datasetprovider1
end
现在我们来看看组的定义。该定义可以通过为索引指定一个分组级别,与索引定义一起获得:
object clientdataset1: tclientdataset
indexdefs = /SPAN
item
name = clientdataset1index1
fields = continent
groupinglevel = 1
end
indexname = clientdtaset1index1
当拥有了一组之后,我们可以在DBGrid中向用户显示分组结构。只需为分组字段(在范例中是Continent字段)处理OnGetText事件,只有 当记录是组的第一个记录是才显示文本:
procedure TForm1.ClientDataSet1ContinentGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
if gbFirst in ClientDataSet1.GetGroupState(1) then
Text:= sender.asstring
else
text:=;
end;
4、定义合计
ClientDataSet组件另一个功能强大的特性是对合计的支持。合计是一个基于多个记录的计算值,如整个数据表格或一组记录(使用我 们刚才讨论过的分组逻辑来定义)中某个字段的和值或平均值。合计是可持续的;也就是说,如果有一个记录发生改变,会立刻重新计算 合计值。例如,当拥护在发货清单条目中输入时,发货单的总和会自动被重新计算出来。
注意:::合计是递增维持的,而不是每当有一个值改动时就重新计算所有的值。合计的更新利用了ClientDataSet追踪的Delta。例如 ,当字段发生改变时,为了更新Sum,ClientDataSet会从合计中读取旧值,并加上新值。只需要两次计算,即使在该合计组中有上千行。 因此,合计更新是瞬时的。
有两种方法定义合计。我们可以使用ClientDataSet(是一个集合)的Aggregates属性,或可以使用Fields编辑器定义合计字段。在这两 种情况下,我们定义的合计表达式,赋给它一个名称,并将它与一个索引和一个分组级别(除非想将它应用于整个数据表格)连接。下面 是CdsCalcs范例的Aggregates集合:
Object ClientDataSet1: TClientDataSet
Aggregates = /SPAN
item
Active = True
AggregateName = Count
Expression = Count(Name)
GroupingLevel = 1
IndexName = ClientDataSet1Index1
Visible = False
end
item
Active = True
AggregateName = TotalPopulation
Expression = SUM(POPULATION)
Visible = False
end
AggregatesActive = True
注意,在上面的最后一行代码中,除了激活每个想使用的特定合计之外,我们还必须为合计激活支持。解除合计是重要的,因为合计太多 会减慢程序执行的速度。我们曾提到的另一种方法是使用Fields编辑器,在其快捷菜单中选择New Field命令,并选择Aggregate选项(只 有在一个ClientDataSet中可以与InternalCalc选项一起使用)。下面是一个合计字段的定义:
Object ClientDataSet1: TClientDataSet
object ClientDataSet1TotalArea: TAggregateField
FieldName = TotalArea
ReadOnly = True
Visible = True
Active = True
DisplayFormat = ###,###,###
Expression = SUM(AREA)
GroupingLevel = 1
IndexName = ClientDataSet1Index1
end
合计字段在Fields编辑器中被显示为独立的一组。与普通合计相比,使用合计字段的优点是,我们可以定义显示格式,并将字段直接 与数据敏感控件相连,如 CdsCalcs范例中的DBEdit。因为合计与一个组相连,所以要选择了另一组的记录,输出就会被自动更新。而且, 如果改变数据,合计值也会立刻显示新值。
为了使用普通合计,必须编写一些代码,如下例子中所示(注意合计的Value是一个变体):
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:= Area : + ClientDataSet1TotalArea.DisplayText +
#13Population : + FormatFloat(###,###,###,ClientDataSet1.Aggregates[1].Value)
+ #13Number : + IntToStr(ClientDataSet1.Aggregates[0].Value);
end;
span "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46202">
p FireMonkey使用Style来控制控件的显示方式。 /p p 每个控件都有一个StyleLookup属性,FireMonkey就是通过控件的这个属性来在当前窗体的StyleBook控件中查找匹配的Style,如果找到了这个Style,那么控件就使用这个Style来显示。 /p p /p p StyleBook是一个Style的集合,里面可以有窗体的Styl
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46210">
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46190">
span "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46189">
p "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46211">
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46207">
p "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46201">
span "author-img" src="https://ucc.alicdn.com/avatar/avatar3.jpg?x-oss-process=image/resize,h_150,m_lfit" />
ClientDataSet组件支持很多特性,其中一些与三级结构有关,而且还可以用在其他环境中。该组件说明了一个数据库完全映象在内存 中,这使得可以进行动态的操作,如建立一个索引,其他数据集合通常不支持该特性。例如,为了对查询分类,我们通常是重新执行它。 为了索引一个局部表格,需要定义索引。只有ADO数据集合有一些与ClientDataSet一样的动态索引功能。
索引并不是ClientDataSet提供的全部功能。当我们拥有了索引之后,可以基于它定义组,可能是多级别的分组。对于确定一个记录在 组中的位置(头、尾或中间位置),甚至有专门的支持。在组或整个数据表格中,我们可以定义总计;也就是说,可以动态计算整个表格 或当前组中一列的总和或平均值。数据不需要发送给物理服务器,因为这些总计操作发生在内存中。我们甚至可以定义新的总计字段,可 以直接与数据敏感控件相连。
注意,所有这些特性不但可以用与MIDAS应用程序,还可以用与客户机/服务器,甚至是局部瘦应用程序。事实上,ClientDataSet组件 可以从远程MIDAS连接、局部数据集合(建立起数据的快照)、或局部文件(就象在公文包模式中一样,但使用的只是在客户机数据集合中 定义的整个表格)中获得起数据。
这是另一个需要研究的领域,所以将向读者演示两个范例来突出关键特性。这些范例没有基于MIDAS,而是基于局部表格。
1、定义抽象的数据的数据类型
VCL数据库支持的一个有趣的特性是,当我们基于局部文件使用ClientDataSet时,可以定义抽象的数据类型。只需在窗体上放置一个 ClientDataSet组件,为FieldDefs属性激活编辑器,添加两个字段,并为他们的DataType属性选择ftADT值。现在,移到 ChildDefs属性, 并定义子字段,下面是AdtDemo范例的字段定义:
FieldDefs = /SPAN
item
Name = ID
DataType = ftInteger
end
item
name = Name
ChildDefs = /SPAN
item
name = LastName
DataType = ftString
size = 20
end
item
name = FirstName
datatype = ftString
size = 20
end
datatype = ftADT
size = 2
end
在此,只需为ClientDataSet的FileName属性输入一个名称,用鼠标右键单击组件,并选择Create Table命令即可;我们准备编译并运 行应用程序(在向它连接数据敏感组件之后)。数据会自动从提供的文件中读取,关闭程序时会将变化保存在文件中。
如果使用DBGrid查看结果数据集合,它允许我们展开或压缩ADT字段的子字段。我们可以通过定义字段的OnGetText事件提供它的压缩 值(在 Delphi4 中有一个缺省值,但Delphi5中没有):
procedure TForm1.ClientDataSet1NameGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
Text:=ClientDataSet1NameFirstName.AsString+ +
ClientDataSet1NameLastName.AsString;
end;
2、动态索引
一旦ClientDataSet上有了数据,数据就已全部处于内存中了。当我们将组件基于局部文件中时(如在AdtDemo范例中),在程序启动 时整个文件就被装载到了内存总。这与从Paradox数据表格中装载数据(BDE只装载正访问的字段)不同。
将整个表格装在内存中的优点是,我们可以快速地对它进行分类。使用ClientDataSet组件,我们可以通过赋给IndexFieldNames属性 相应的字段名来实现分类。在AdtDemo(以及很多程序)中,该索引变动会在单击DBGrid控件的标题(触发OnTitleClick事件)时执行:
procedure TForm1.DBGrid1TitleClick(Column:TColumn);
begin
if Column.Field.FullName = Name then
ClientDataSet1.IndexFieldNames := Name.LastName
else
ClientDataSet1.IndexFieldNames := Column.Field.FullName;
end;
由于ADT定义,程序使用了字段的FullName属性(而不是FieldName属性)。事实上,对于子字段来说,索引应该基于 Name.LastName, 而不是LastName。而且ADT字段不能自己被索引,所以如果选择它,程序会使用LastName子字段作为索引。这些索引不是持久性的;它们没 有保存在文件中,而只是在内存中应用于数据。
技巧:ClientDataSet可以拥有基于计算字段的索引,特别是内部计算字段,这种字段类型只能用于该数据集合。
3、分组
一旦为ClientDataSet定义了一个索引,就可以通过该索引对数据进行分组了。实际上,一组被定义为连续记录的一个列表(根据索引 ),记录中被索引的字段的值不会改变。例如,如果有一个基于国家的索引,带有该国家的所有地址都将归为一组。
cdsCalcs范例有一个ClientDataSet组件,它同样从DBDEMOS数据库的Country表格中读取其数据。该操作可以在设计时,使用 ClientDataSet组件快捷菜单的Assign Local Data命令来执行。为了在运行时读取数据,获得一个更新的快照,可以向窗体添加一个 DataSetProvider组件,如下连接三个组件:
Object Table :TTable
active = true
databasename = dbdemos
tablename = country.db
end
object datasetprovider1: TDataSetProvider
dataset = table1
end
object clientdataset1: tclientdataset
providername = datasetprovider1
end
现在我们来看看组的定义。该定义可以通过为索引指定一个分组级别,与索引定义一起获得:
object clientdataset1: tclientdataset
indexdefs = /SPAN
item
name = clientdataset1index1
fields = continent
groupinglevel = 1
end
indexname = clientdtaset1index1
当拥有了一组之后,我们可以在DBGrid中向用户显示分组结构。只需为分组字段(在范例中是Continent字段)处理OnGetText事件,只有 当记录是组的第一个记录是才显示文本:
procedure TForm1.ClientDataSet1ContinentGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
if gbFirst in ClientDataSet1.GetGroupState(1) then
Text:= sender.asstring
else
text:=;
end;
4、定义合计
ClientDataSet组件另一个功能强大的特性是对合计的支持。合计是一个基于多个记录的计算值,如整个数据表格或一组记录(使用我 们刚才讨论过的分组逻辑来定义)中某个字段的和值或平均值。合计是可持续的;也就是说,如果有一个记录发生改变,会立刻重新计算 合计值。例如,当拥护在发货清单条目中输入时,发货单的总和会自动被重新计算出来。
注意:::合计是递增维持的,而不是每当有一个值改动时就重新计算所有的值。合计的更新利用了ClientDataSet追踪的Delta。例如 ,当字段发生改变时,为了更新Sum,ClientDataSet会从合计中读取旧值,并加上新值。只需要两次计算,即使在该合计组中有上千行。 因此,合计更新是瞬时的。
有两种方法定义合计。我们可以使用ClientDataSet(是一个集合)的Aggregates属性,或可以使用Fields编辑器定义合计字段。在这两 种情况下,我们定义的合计表达式,赋给它一个名称,并将它与一个索引和一个分组级别(除非想将它应用于整个数据表格)连接。下面 是CdsCalcs范例的Aggregates集合:
Object ClientDataSet1: TClientDataSet
Aggregates = /SPAN
item
Active = True
AggregateName = Count
Expression = Count(Name)
GroupingLevel = 1
IndexName = ClientDataSet1Index1
Visible = False
end
item
Active = True
AggregateName = TotalPopulation
Expression = SUM(POPULATION)
Visible = False
end
AggregatesActive = True
注意,在上面的最后一行代码中,除了激活每个想使用的特定合计之外,我们还必须为合计激活支持。解除合计是重要的,因为合计太多 会减慢程序执行的速度。我们曾提到的另一种方法是使用Fields编辑器,在其快捷菜单中选择New Field命令,并选择Aggregate选项(只 有在一个ClientDataSet中可以与InternalCalc选项一起使用)。下面是一个合计字段的定义:
Object ClientDataSet1: TClientDataSet
object ClientDataSet1TotalArea: TAggregateField
FieldName = TotalArea
ReadOnly = True
Visible = True
Active = True
DisplayFormat = ###,###,###
Expression = SUM(AREA)
GroupingLevel = 1
IndexName = ClientDataSet1Index1
end
合计字段在Fields编辑器中被显示为独立的一组。与普通合计相比,使用合计字段的优点是,我们可以定义显示格式,并将字段直接 与数据敏感控件相连,如 CdsCalcs范例中的DBEdit。因为合计与一个组相连,所以要选择了另一组的记录,输出就会被自动更新。而且, 如果改变数据,合计值也会立刻显示新值。
为了使用普通合计,必须编写一些代码,如下例子中所示(注意合计的Value是一个变体):
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:= Area : + ClientDataSet1TotalArea.DisplayText +
#13Population : + FormatFloat(###,###,###,ClientDataSet1.Aggregates[1].Value)
+ #13Number : + IntToStr(ClientDataSet1.Aggregates[0].Value);
end;
span "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46202">
p FireMonkey使用Style来控制控件的显示方式。 /p p 每个控件都有一个StyleLookup属性,FireMonkey就是通过控件的这个属性来在当前窗体的StyleBook控件中查找匹配的Style,如果找到了这个Style,那么控件就使用这个Style来显示。 /p p /p p StyleBook是一个Style的集合,里面可以有窗体的Styl
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46210">
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46190">
span "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46189">
p "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46211">
div "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46207">
p "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/46201">
span "author-img" src="https://ucc.alicdn.com/avatar/avatar3.jpg?x-oss-process=image/resize,h_150,m_lfit" />
相关文章
- MongoDB介绍
- ImGui-imgui介绍
- JRainbow的简单介绍
- 【MySql】mysql 的权限体系介绍
- java中ThreadLocal类的详细介绍(详解)
- Java中构造方法的详细介绍
- linux配置网卡IP地址命令详细介绍及一些常用网络配置命令
- 一种基于事件驱动思想的 SAP 系统集成二次开发方法介绍
- 介绍一个能开发简单SAP UI5应用的在线IDE:StackBlitz
- DL之VGGNet:VGGNet算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- DL之GCN:GCN算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- DL之PanopticFPN:Panoptic FPN算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- DL之AlexNet:AlexNet算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- 【高并发】不废话,言简意赅介绍BlockingQueue
- Win10系统病毒隔离文件在哪里?详细位置介绍
- 这篇文章可以说是功能测试与非功能测试最详细的介绍了
- python基础===discover函数介绍
- 【postgres】超详细介绍
- Python图像处理PIL各模块详细介绍
- 7种抓包工具详细介绍
- 内网渗透之MSF框架模块详细作用介绍