ClientDataSet 心得
1. 与TTable、TQuery一样,TClientDataSet也是从TDataSet继承下来的,它通常用于多层体系结构的客户端。很多数据库应用程序都用了BDE,BDE往往给发布带来很大的不便,因而TClientDataSet最大的特点是它不依赖于BDE(Borland Database Engine),但它需要一个动态链接库的支持,这个动态链接库叫DBCLIENT.DLL。在客户端,也不需要用TDatabase构件,因为客户端并不直接连接数据库。由于TClientDataSet是从TDataSet继承下来的,所以,它支持诸如编辑、搜索、浏览、纠错、过滤等功能。由于 TClientDataSet在内存中建立了数据的本地副本,上述操作的执行速度很快。也正是由于TClientDataSet并不直接连接数据库,因此,客户程序必须提供获取数据的机制。
在Delphi 4中,TClientDataSet有三种途径获取数据:
1、从文件中存取数据。
2、从本地的另一个数据集中获取数据。
3、通过IProvider接口从远程数据库服务器获取数据。
在一个客户程序中,可以同时运用上述三种机制获取数据。
和其他数据集构件一样,可以用标准的数据控件显示由TClientDataSet引入的数据集,当然,这需要借助于TDataSource构件。由于 TClientDataSet是从TDataSet继承下来的,所以,凡是其他数据集构件支持的功能,TClientDataSet构件也大致具备。不同的是,TClientDataSet能够在内存中建立数据的副本,因此,TClientDataSet比其他数据集构件增加了一些特殊的功能。
在运行期,可以调用诸如First、GotoKey、Last、Next和Prior等函数来浏览数据。TClientDataSet也支持书签 (BookMark)功能,可以用书签来标记某条记录,以后就可以方便地找到这条记录。对于TTable、TQuery等数据集构件来说,只能读 RecNo属性来判断当前记录的序号。对于TClientDataSet构件来说,还可以写RecNo属性,使某一序号的记录成为当前记录。
1、从文件中存取数据要从文件中读取数据,可以调用LoadFromFile函数。LoadFromFile函数需要传递一个参数,用于指定文件名。文件名应包含完整的路径。如果客户程序总是从一个固定的文件中读取数据,可以设置FileName属性指定一个文件名,以后,当TClientDataSet 引入的数据集打开时,就自动从这个文件中读取数据,不需要调用LoadFromFile。要从流中读取数据,可以调用LoadFromStream。 LoadFromStream需要传递一个参数,用于指定一个流对象。注意:LoadFromFile(LoadFromStream)只能从先前用 SaveToFile(SaveToStream)保存的文件中读取数据。要把数据保存到文件中,可以调用SaveToFile函数。 SaveToFile需要传递一个参数,用于指定文件名。如果指定的文件已存在,文件中的数据将被覆盖。如果客户程序总是把数据保存到一个固定的文件中,可以设置FileName属性指定一个文件名,当TClientDataSet引入的数据集关闭时,就自动把数据保存到这个文件中,不需要调用 SaveToFile。要把数据保存到流中,可以调用SaveToStream。SaveToStream需要传递一个参数,指定一个流对象。注意:当把数据保存到文件或流中时,日志中记载的修改仍然保留。这样,当下次调用LoadFromFile或LoadFromStream读取数据时,仍然可以恢复原来的数据。
ClientDataSet强大的数据复制技术:
通过ClientDataSet.Data属性可以访问客户程序从应用服务器检索到的数据。程序示例如下:
- Procedure TForm1.Button1Click(Sender: TObject);
- Begin
- ClientDataSet1.Data :=
- ClientDataSet1.Provider.DataRequest(FilterEdit.Text);//在Delphi4版本之上有所改变
- End;
也可以直接赋值:
ClientDataSet1.Data:=ClientDataSet2.Data;//(相当于把ClientDataSet2的数据拷贝给ClientDataSet1,是不是很方便)
从其他数据集获取数据(除ClientDataSet):
- DataSetProvider1.DataSet:=DataSet;//DataSet代表一个数据集
- ClientDataSet1.Data := DataSetProvider1.Data;
3. 排序
ClientDataSet排序
1、简单排序
- ClientDataSet1.IndexFieldNames:='排序字段'
2、复杂排序(建立索引)
下面这个过程仅供参考(因为用到三方控件DBGridEh):
- procedure TDM1.DsSort(SortColumn: TColumnEh);
- var
- OldIndex:string;
- begin
- if (SortColumn.Grid.DataSource=nil) or (SortColumn.Grid.DataSource.DataSet=nil) or (not SortColumn.Grid.DataSource.DataSet.Active) then Exit;
- OldIndex:=TClientDataSet(SortColumn.Field.DataSet).IndexName;
- if OldIndex<>'' then
- begin
- TClientDataSet(SortColumn.Field.DataSet).IndexName:='';
- TClientDataSet(SortColumn.Field.DataSet).DeleteIndex(OldIndex);
- end;
- case SortColumn.Title.SortMarker of
- smNoneEh,
- smUpEh :TClientDataSet(SortColumn.Field.DataSet).AddIndex('px',SortColumn.Field.FieldName,[ixDescending]);
- smDownEh:TClientDataSet(SortColumn.Field.DataSet).AddIndex('px',SortColumn.Field.FieldName,[ixPrimary]);
- end;
- TClientDataSet(SortColumn.Field.DataSet).IndexName:='px';
- end;
把上面的过程稍做修改,可用于标准DBGridvar
- ASC:Boolean=True;//是否升序排列
- procedure TDM1.DsSort(SortColumn: TColumn);
- var
- OldIndex:string;
- begin
- if (SortColumn.Grid.DataSource=nil) or (SortColumn.Grid.DataSource.DataSet=nil) or (not SortColumn.Grid.DataSource.DataSet.Active) then Exit;
- OldIndex:=TClientDataSet(SortColumn.Field.DataSet).IndexName;
- if OldIndex<>'' then
- begin
- TClientDataSet(SortColumn.Field.DataSet).IndexName:='';
- TClientDataSet(SortColumn.Field.DataSet).DeleteIndex(OldIndex);
- end;
- case ASC of
- Ture :TClientDataSet(SortColumn.Field.DataSet).AddIndex('px',SortColumn.Field.FieldName,[ixDescending]);//已经是升序就按降序排列
- else//否则按升序排列
- TClientDataSet(SortColumn.Field.DataSet).AddIndex('px',SortColumn.Field.FieldName,[ixPrimary]);
- end;{end case}
- TClientDataSet(SortColumn.Field.DataSet).IndexName:='px';
- ASC:=not ASC;
- end;
4. 提交更新过程:
首先,客户程序要调用ApplyUpdates函数向应用服务器提出申请,ApplyUpdates函数将通过IProvider接口把Delta(数据变动情况)属性传递给应用服务器。应用服务器收到客户程序的申请后,再向远程数据库服务器提出申请,并且把被远程数据库服务器认为出错的记录暂时缓存起来。应用服务器上的TDataSetProvider或TProvider构件把出错的记录返回给客户程序,其中包括错误信息和错误代码。客户程序收到这些出错的记录后,可以进行核对和修改,然后继续更新。注意:如果应用服务器端使用MTS类型的远程数据模块,就无法提供IProvider接口,这种情况下,必须通过远程数据模块的接口直接申请更新数据。
if ClientDataSet1.ChangeCount>0 then//有未决的修改
ClientDataSet1.ApplyUpdates(MaxErrors);//将修改提交到服务器
参数MaxErrors用于指定一个最大错误数,如果出错的记录数超过了这个参数的值,此次更新就停止。如果MaxErrors参数设为0,只要应用服务器发现有一个错误的记录,更新操作就停止。如果MaxErrors参数设为-1,当应用服务器发现有错误的记录,就尝试更新下一个记录,等所有的记录都尝试过以后才返回。ApplyUpdates函数将返回实际遇到的错误数,同时,应用服务器将返回那些有错误的记录。
当应用服务器收到客户的提交请求后,触发OnUpdateData,这时就可以对客户提交的数据进行检查和编辑:
如
Procedure TDataModule1.Provider1UpdateData(Sender:TObject;DataSet: TClientDataSet);
Begin
With DataSet Do
Begin
First;
While not Eof Do
Begin
If UpdateStatus = usInserted then
Begin
Edit;
FieldByName('DateCreated').AsDateTime := Date;
Post;
End;
Next;
End;
End;
End;
然后将编辑后的数据提交到数据库服务器。
ClientDataSet1.CancelUpdates;//恢复所有修改过但未提交(包括提交未成功的)的记录
ClientDataSet1.UndoLastChange;//恢复前一次的修改,相当于Undo功能
注意使用这种提交方式(ApplyUpdates)在查询时尽可能避免使用数据处理(关联、分组、求和等等等),否则不能提交(除非自己写一些特殊处理程序)
1.动态索引
procedure TForm1.DBGrid1TitleClick(Column: TColumn); begin
if (not column.Field is Tblobfield) then//Tblobfield不能索引,二进制
ClientDataSet1.IndexFieldNames:=column.Field.FieldName;
end;</span>
设主表ClientDataSet1.packetrecord为-1,所有记录
设从表ClientDataSet1.packetrecord为0,当前记录
3.Taggregates使用
(1)在字段编辑中add new field类型为aggregates
后设置expression(表达试)
设置active:=true即可
使用dbedit的field为前者即可
(2)使用Aggergates属性add设计表达试
调用
- <span style="font-size:13px;"> showmessage(floattostr(ClientDataSet1.Aggregates.Count));
- showmessage(ClientDataSet1.Aggregates.Items[0].Value);</span>
使用ClientDataSet代替table,使用ClientDataSet的loadfilename装入cds
代替table的tablename的db或者dbf
原来的程序改造方法:
加一个ClientDataSet,使用右键assign locate data
后savetofile,再loadfromfile,后删除table
将原连table的datasource设为ClientDataSet
唯一注意的是:要将midas.dll拷到system或者当前目录
5.三层结构的公文包的实现方法
同时设定1:filename(*.cds)2.remote server
6.可以对data赋值(从另一个数据集取值)
ClientDataSet2.Data:=ClientDataSet1.Data;
ClientDataSet2.Open;
ClientDataSet2.CloneCursor(ClientDataSet1,true);
ClientDataSet2.Open;
客户程序向应用服务器请求数据。如果TClientDataSet 的
FetchOnDemand 属性设为True,
客户程序会根据需要自动检索附加的数据包如BLOB字段的值或嵌套表的内容。
否则,
客户程序需要显式地调用GetNextPacket 才能获得这些附加的数据包。
ClientDataSet的packetrecords设置一次取得的记录个数
(1)sql内容为空
- <span style="font-size:13px;">ClientDataSet1.Close;
- ClientDataSet1.CommandText:=edit1.Text;//即sql内容
- ClientDataSet1.Open;</span>
filtered=true可实现sql功能
(2)有参数
如服务端query的sql为
select * from animals
where name like :dd
则:客户端ClientDataSet
- <span style="font-size:13px;">var
- pm:Tparam;
- begin
- ClientDataSet1.Close;
- ClientDataSet1.ProviderName:='DataSetProvider1';
- pm:=Tparam.Create(nil);
- pm.Name:='dd';
- pm.DataType:=ftString;
- ClientDataSet1.Params.Clear;
- ClientDataSet1.Params.AddParam(pm);
- ClientDataSet1.Params.ParamByName('dd').AsString:=edit1.Text ;
- ClientDataSet1.Open;
- pm.Free;
- end;
- </span>
9.数据的更新管理
(1)savepoint 保存目前为止数据状态,可以恢复到这个状态
var
pp:integer;
begin
pp:=ClientDataSet1.SavePoint;
ClientDataSet1.Edit;
ClientDataSet1.FieldByName('姓名').asstring:='古话';
ClientDataSet1.Post;
table1.Refresh;
end;
恢复点
ClientDataSet1.SavePoint:=pp;
(2)cancel,RevertRecord
取消对当前记录的修改,只适合没有post的,如果post,调用
RevertRecord
(3)cancelupdate
取消对数据库所有的修改
(4)UndoLastChange(boolean),changecount
取消上一次的修改,可以实现连续撤消
参数为true:光标到恢复处
false:光标在当前位置不动
changecount返回修改记录的次数,一个记录修改多次,返回只一次
但UndoLastChange只撤消一次
10.可写的recno
对于Ttable和Tquery的recno是只读的,而TClientDataSet的recno可读可写
ClientDataSet1.recno:=5;是设第五个记录为当前记录
11.数据保存
对于table使用post可更新数据
而ClientDataSet1的post只更新内存数据,要更新服务器数据要使用
ApplyUpdates(MaxErrors: Integer),他有一个参数,是允许发出错误的
次数,-1表示无数次,使用simpleobjectbroker时常设为0,实现自动容错和负载平衡
TClientDataSet是Delphi开发数据库时一个非常好的控件。有很强大的功能。
我常常用ClientDataSet做MemoryDataSet来使用。还可以将ClientDataSet的数据保存为XML,这样就可以做简单的本地数据库使用。还有很多功能就不多说了。在使用ClientDataSet的过程中关于怎样提高处理速度这个问题,我就我个人的一点点体会和大家分享一下。
通常情况下我们一般都是用
...ClientDataSet-->DataSource-->DBComponent
这样的结构,处理数据的时候就直接操作ClientDataSet。但是大多DBComponet都会立即响应ClientDataSet的变化。如果你是向ClientDataSet中插入很多数据时候,DBComponent就要响应几次,而且响应过程根据不同的控件,速度,过程数量都不一样。这样就影响了程序的执行效率 。所以在对ClientDataSet处理中,我是用ClientDataSet.DisableControls和ClientDataSet.EnableControls方法:打开和关闭DBComponent与ClientDataSet的数据显示关系。
例如:
- <span style="font-size:13px;">ClientDataSet..DisableControls;
- ...
- for I := 0 to 10000 do
- begin
- ClientDataSet.Append;
- ...
- ClientDataSet.Post;
- end;
- ...
- ClientDataSet.EnableControls
- ...
- </span>
ClientDataSet的数据查找。
我所介绍的心得和技巧都是用ClientDataSet来做范例,也可以应用于其他的一些DataSet。废话就不多说了。我们还是先看代码,让后再总结。
1.Scanning 扫描数据查找
这是最简单最直接也是最慢的一种方法,遍历所有数据:
- <span style="font-size:13px;">procedure TForm1.ScanBtnClick(Sender: TObject);
- var
- Found: Boolean;
- begin
- Found := False;
- ClientDataSet1.DisableControls;
- Start;
- try
- ClientDataSet1.First;
- while not ClientDataSet1.Eof do
- begin
- if ClientDataSet1.Fields[FieldListComboBox.ItemIndex].value = SearchText then
- begin
- Found := True;
- Break;
- end;
- ClientDataSet1.Next;
- end;
- Done;
- finally
- ClientDataSet1.EnableControls;
- end;
- if Found then
- ShowMessage(SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo))
- else
- ShowMessage(ScanForEdit.Text + ' not found');
- end;</span>
最老,但是最快 的查找方式。
使用FindKey/FindNearest来查找一条或多条符合条件的数据,当然待查找的Field必须是一个IndexField 。可以看出,这种基于Index的查找速度是非常快的。
- <span style="font-size:13px;">procedure TForm1.FindKeyBtnClick(Sender:TObject);
- begin
- Start;
- if ClientDataSet1.FindKey([SearchText]) then
- begin
- Done;
- StatusBar1.Panels[3].Text := SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
- end
- else
- begin
- Done;
- StatusBar1.Panels[3].Text := SearchText + ' not found';
- end;
- end;
- procedure TForm1.FindNearestBtnClick(Sender: TObject);
- begin
- Start;
- ClientDataSet1.FindNearest([SearchText ]);
- Done;
- StatusBar1.Panels[3].Text := 'The nearest match to ' + SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
- end</span>
GotoKey/GotoNearest 与FindKey/FindNearest基本上没有什么区别。它也是基于Index的查找。唯一的区别就是在于你是怎么定义你的查找了。代码上也有区别:
- <span style="font-size:13px;">ClientDataSet1.SetKey;
- ClientDataSet1.FieldByName(IndexFieldName).value := SearchText;
- ClientDataSet1.GotoKey;</span>
- <span style="font-size:13px;">ClientDataSet1.FindKey([SearchText]);</span>
要用好这两种基于Index的查找,还需要了解ClientDataSet和Index机制。这里就不详细说明Index机制。一个基本的原则,要有Index,才能查找。
4.Locating 查找数据
2,3两种查找方式都是基于Index的,但是在实际应用中,可能会查找IndexField以外的Field。那我们就可以使用Locate。但是查找速度是没有2,3两种快的。比如:如果你查找一条纪录9000/10000,Locate需要500ms,Scanning需要>2s,FindKey只要10ms(但是当你打开ClientData的时候,建立Index需要1s)。
- <span style="font-size:13px;">procedure TForm1.LocateBtnClick(Sender: TObject);
- begin
- Start;
- if ClientDataSet1. Locate('Field1,Field2..',VarArrayOf['value1,value2..'], []) then
- begin
- Done;
- StatusBar1.Panels[3].Text := 'Match located at record ' +
- IntToStr(ClientDataSet1.RecNo);
- end
- else
- begin
- Done;
- StatusBar1.Panels[3].Text := 'No match located';
- end;
- end;</span>
小结:
ClientDataSet提供了好多种查找数据的方法。但是各自有其优缺点。
上面的例子中有Start;和Done,如果你有兴趣,可以加入计时点进行速度测试。
Scanning最简单,但是最慢,因为比较慢,还得使用ClientDataSet.DisableControls和ClientDataSet.EnableControls方法(我在前面一片文章讲过)。
Findkey/FindNearest(GotoKey/GotoNearest)代码多,但是非常快。必须使用Index,不同的是Find需要的Index是必须建立好的,而Goto可以在第一次使用时建立Index。
Locate使用最方便,不需要Index,但是速度没有Find快
ClientDataSet使用心得和技巧 影响ClientDataSet处理速度的一个因素
TClientDataSet是Delphi开发数据库时一个非常好的控件。有很强大的功能。
我常常用ClientDataSet做MemoryDataSet来使用。还可以将ClientDataSet的数据保存为XML,这样就可以做简单的本地数据库使用。还有很多功能就不多说了。在使用ClientDataSet的过程中关于怎样提高处理速度这个问题,我就我个人的一点点体会和大家分享一下。
通常情况下我们一般都是用
...ClientDataSet-->DataSource-->DBComponent
这样的结构,处理数据的时候就直接操作ClientDataSet。但是大多DBComponet都会立即响应ClientDataSet的变化。如果你是向ClientDataSet中插入很多数据时候,DBComponent就要响应几次,而且响应过程根据不同的控件,速度,过程数量都不一样。这样就影响了程序的执行效率。所以在对ClientDataSet处理中,我是用ClientDataSet.DisableControls和ClientDataSet.EnableControls方法:打开和关闭DBComponent与ClientDataSet的数据显示关系。
例如:
ClientDataSet..DisableControls;
...
for I := to do
begin
ClientDataSet.Append;
...
ClientDataSet.Post;
end;
...
ClientDataSet.EnableControls
...
这样做以后你会发现处理速度比以前没有使用方法的时候有成倍的提高。 ClientDataSet的数据查找。
我所介绍的心得和技巧都是用ClientDataSet来做范例,也可以应用于其他的一些DataSet。废话就不多说了。我们还是先看代码,让后再总结。
.Scanning 扫描数据查找
这是最简单最直接也是最慢的一种方法,遍历所有数据:
procedure TForm1.ScanBtnClick(Sender: TObject);
var
Found: Boolean;
begin
Found := False;
ClientDataSet1.DisableControls;
Start;
try
ClientDataSet1.First;
while not ClientDataSet1.Eof do
begin
if ClientDataSet1.Fields[FieldListComboBox.ItemIndex].value = SearchText then
begin
Found := True;
Break;
end;
ClientDataSet1.Next;
end;
Done;
finally
ClientDataSet1.EnableControls;
end; if Found then
ShowMessage(SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo))
else
ShowMessage(ScanForEdit.Text + ' not found');
end;
procedure TForm1.ScanBtnClick(Sender: TObject);
var
Found: Boolean;
begin
Found := False;
ClientDataSet1.DisableControls;
Start;
try
ClientDataSet1.First;
while not ClientDataSet1.Eof do
begin
if ClientDataSet1.Fields[FieldListComboBox.ItemIndex].value = SearchText then
begin
Found := True;
Break;
end;
ClientDataSet1.Next;
end;
Done;
finally
ClientDataSet1.EnableControls;
end; if Found then
ShowMessage(SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo))
else
ShowMessage(ScanForEdit.Text + ' not found');
end; .Finding 寻找数据
最老,但是最快的查找方式。
使用FindKey/FindNearest来查找一条或多条符合条件的数据,当然待查找的Field必须是一个IndexField。可以看出,这种基于Index的查找速度是非常快的。 procedure TForm1.FindKeyBtnClick(Sender: TObject);
begin
Start;
if ClientDataSet1.FindKey([SearchText]) then
begin
Done;
StatusBar1.Panels[].Text := SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
end
else
begin
Done;
StatusBar1.Panels[].Text := SearchText + ' not found';
end;
end; procedure TForm1.FindNearestBtnClick(Sender: TObject);
begin
Start;
ClientDataSet1.FindNearest([SearchText]);
Done;
StatusBar1.Panels[].Text := 'The nearest match to ' + SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
end
procedure TForm1.FindKeyBtnClick(Sender: TObject);
begin
Start;
if ClientDataSet1.FindKey([SearchText]) then
begin
Done;
StatusBar1.Panels[].Text := SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
end
else
begin
Done;
StatusBar1.Panels[].Text := SearchText + ' not found';
end;
end; procedure TForm1.FindNearestBtnClick(Sender: TObject);
begin
Start;
ClientDataSet1.FindNearest([SearchText]);
Done;
StatusBar1.Panels[].Text := 'The nearest match to ' + SearchText + ' found at record ' + IntToStr(ClientDataSet1.RecNo);
end .Going 定位
GotoKey/GotoNearest 与FindKey/FindNearest基本上没有什么区别。它也是基于Index的查找。唯一的区别就是在于你是怎么定义你的查找了。代码上也有区别:
ClientDataSet1.SetKey;
ClientDataSet1.FieldByName(IndexFieldName).value := SearchText;
ClientDataSet1.GotoKey;
就相当于
ClientDataSet1.FindKey([SearchText]);
要用好这两种基于Index的查找,还需要了解ClientDataSet和Index机制。这里就不详细说明Index机制。一个基本的原则,要有Index,才能查找。 .Locating 查找数据
,两种查找方式都是基于Index的,但是在实际应用中,可能会查找IndexField以外的Field。那我们就可以使用Locate。但是查找速度是没有2,两种快的。比如:如果你查找一条纪录9000/,Locate需要500ms,Scanning需要>2s,FindKey只要10ms(但是当你打开ClientData的时候,建立Index需要1s)。
procedure TForm1.LocateBtnClick(Sender: TObject);
begin
Start;
if ClientDataSet1.Locate('Field1,Field2..',VarArrayOf['value1,value2..'], []) then
begin
Done;
StatusBar1.Panels[].Text := 'Match located at record ' + IntToStr(ClientDataSet1.RecNo);
end
else
begin
Done;
StatusBar1.Panels[].Text := 'No match located';
end;
end; ClientDataSet提供了好多种查找数据的方法。但是各自有其优缺点。
上面的例子中有Start;和Done,如果你有兴趣,可以加入计时点进行速度测试。
Scanning最简单,但是最慢,因为比较慢,还得使用ClientDataSet.DisableControls和ClientDataSet.EnableControls方法(我在前面一片文章讲过)。
Findkey/FindNearest(GotoKey/GotoNearest)代码多,但是非常快。必须使用Index,不同的是Find需要的Index是必须建立好的,而Goto可以在第一次使用时建立Index。
Locate使用最方便,不需要Index,但是速度没有Find快。 var
sFields : String;
vResult : Variant;
iCount : Integer;
begin
vResult := ds.Lookup('fieldnameA, fieldnameB' , VarArrayCreate([ValueA, ValueB], varVariant), 'fieldname1, fieldname2');
if (VarIsArray(vResult)) then
begin
sFields := '';
for iCount := VarArrayLowBound(vResult, ) to VarArrayHighBound(vResult, ) do
begin
sFields := sFields + ';' + vResult[iCount];
end;
end
else
edtReturn.Text := vResult;
end;
ClientDataSet 心得的更多相关文章
- ClientDataSet
TField对象的SetText和GetText事件处理函数 使用TField对象的SetText和GetText事件处理函数可方便的解决字段的代码与代码所对应值的显示问题 TSimpleDatase ...
- delphi clientdataset判断某一行值是否存在
ClientDataSet的数据查找.我所介绍的心得和技巧都是用ClientDataSet来做范例,也可以应用于其他的一些DataSet.废话就不多说了.我们还是先看代码,让后再总结.1.Scanni ...
- DELPHI 数据库控件心得
TField对象的SetText和GetText事件处理函数 使用TField对象的SetText和GetText事件处理函数可方便的解决字段的代码与代码所对应值的显示问题 TSimpleDatase ...
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- NoSql数据库使用半年后在设计上面的一些心得
NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(三) 查看字段长度
我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(五) 运算符
我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
随机推荐
- 最佳运动类APP-Keep设计与欣赏
运动类APP是大家手机中必备的一款软件.如果说谁手机里没有任何涉及运动类APP,那只能说真的与时代脱轨了.近些年随着物质生活条件的改善,人们开始越来越重视自己的身体,所以也越来越多的人会进行身体锻炼. ...
- .NET TCP协议之TcpClient与TcpListener交互
问题:手机某项功能服务需要采用TCP协议与第三方交互通信.需先在公司内部测试此功能. 原因:第三方没有任何消息返回,也没有客服提供服务. 解决方法:公司内部做一个TCP协议服务器端,根据外网ip+端口 ...
- 深入理解python里面类的对象的赋值
class T(): def __init__(self): self.name= pass a=T() a.name= b=a #深入理解类,类里面的对象的赋值是指针赋值,也就是同时变的 b.nam ...
- django 静态文件
django中的静态文件,如图片,css样式jquery等等 在url最下面加上 from django.conf.urls.static import staticfrom django.conf ...
- 【WebService】WebService之WSDL文档深入分析(三)
WSDL概念 WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问. ...
- 进制转换(NOIP2000&NOIP水题测试(2017082301))
题目链接:进制转换 这题得明白其中的数学方法,明白后就不难了. 那么我们应该怎么计算呢? 其实也很简单. 我们依然采取辗转相除法. 但是,对于负的余数,我们需要进行一些处理. 我们怎么处理呢? 很简单 ...
- keras框架的CNN手写数字识别MNIST
参考:林大贵.TensorFlow+Keras深度学习人工智能实践应用[M].北京:清华大学出版社,2018. 首先在命令行中写入 activate tensorflow和jupyter notebo ...
- rails gem更换ruby-china源
查看gem源 gem sources -l 换添加源 gem sources --add https://gems.ruby-china.com/ 删除原来的rubygems源 gem sources ...
- (14)Why some people find exercise harder than others
https://www.ted.com/talks/emily_balcetis_why_some_people_find_exercise_harder_than_others/transcript ...
- boost--signal
1.signals2库 signals2库实现了线程安全的观察者模式,在signals2中观察者模式被称为信号/插槽(signals/slots),它是一种函数回调机制.一个信号可以关联一个或多个插槽 ...