数据库的BLOB字段,可以用来保存字节流数据,比如图片、声音文件、html文档和大文本等等。Delphi传统的DataSnap技术,客户端数据集的数据包缺省不包含Blob字段数据,但可以在真正需要的时刻,实时自动从数据库取得,这种自动实现是基于IAppServer接口的。但在DataSnap 2009中,中间层通过方法调用返回TDataSet的时候,客户端无法再通过IAppServer接口取得Blob字段数据了,因为这是方法调用方式,没有IAppServer接口的实现。要解决客户端读取Blob字段数据的问题,可以在中间层单独申明和定义一个返回Blob字段数据流的方法,客户端在适当的时机调用此方法就可以返回Blob字段数据了。下面以一个简单例子说明整个读写过程的实现。
假设我们有一个Oracle的Poster表,保存电影的海报信息。包含两个字段:
Film_id Integer
Picture BLOB
中间层返回海报表中的所有记录:
1
2
3
4
5
6
7
8
9
10
|
function
TMoviesMethods
.
GetPictures: TDataSet;
begin
with
dsQuery
do
begin
Close;
CommandText :=
'select * from poster'
;
Open;
end
;
Result := dsQuery;
end
;
|
中间层再定义一个根据指定ID返回图片数据流的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function
TMoviesMethods
.
GetPictureById(film_id:
Integer
): TStream;
begin
Result :=
nil
;
with
dsQuery
do
begin
Close;
CommandText :=
'select * from poster where film_id=:film_id'
;
ParamByName(
'film_id'
).AsInteger := film_id;
Open;
if
not
eof
then
Result := CreateBlobStream(FieldByName(
'picture'
), bmRead);
end
;
end
;
|
客户端用一个TClientDataSet控件来接收数据,用一个TEdit显示当前记录的ID,一个TImage控件显示当前记录的图片。当TClientDataSet.AfterScroll事件发生时,填写TEdit和TImage控件的内容,其中,TMoviesMethodsClient是自动生成的中间层方法的客户端代理类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
procedure
TForm1
.
ClientDataSet1AfterScroll(DataSet: TDataSet);
var
ResultStream: TStream;
ServiceProxy: TMoviesMethodsClient;
begin
Edit1
.
Text := IntToStr(ClientDataSet1
.
FieldByName(
'film_id'
).AsInteger);
ServiceProxy := TMoviesMethodsClient
.
Create(SQLConnection1
.
DBXConnection);
try
ResultStream := ServiceProxy
.
GetPictureById(ClientDataSet1
.
FieldByName(
'film_id'
).AsInteger);
if
ResultStream <>
nil
then
begin
Image1
.
Picture
.
Bitmap
.
LoadFromStream(ResultStream);
end
;
finally
ServiceProxy
.
Free;
end
;
end
;
|
接下来,演示客户端新增一条记录,为Blob字段添加图片数据,并写回数据库的过程。
客户端新增一条记录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
procedure
TForm1
.
Button1Click(Sender: TObject);
var
AStream: TMemoryStream;
begin
with
ClientDataSet1
do
begin
AStream := TMemoryStream
.
Create;
try
Image1
.
Picture
.
Graphic
.
SaveToStream(AStream);
Append;
FieldByName(
'film_id'
).AsInteger := StrToInt(Edit1
.
Text);
TBlobField(FieldByName(
'picture'
)).LoadFromStream(AStream);
Post;
finally
AStream
.
Free;
end
;
end
;
end
;
|
向中间层提交更新。其中,SavePictures方法是中间层实现的一个方法:
1
2
3
4
5
6
7
8
9
|
procedure
TForm1
.
Button2Click(Sender: TObject);
begin
with
SqlServerMethod1
do
begin
ServerMethodName :=
'TMoviesMethods.SavePictures'
;
ParamByName(
'PosterDelta'
).Value := ClientDataSet1
.
Delta;
ExecuteMethod;
end
;
end
;
|
中间层实现保存Delta数据包的方法。过程中,用到一个TDataSetProvider控件dspUpdate,利用它来解析Delta包,生成SQL语句,提交数据库执行;UpdatePosterDelta过程真正实现手动更新Delta包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
function
TMoviesMethods
.
SavePictures(PosterDelta: OleVariant):
Boolean
;
var
ErrorCount:
Integer
;
begin
Result :=
False
;
if
not
VarIsError(PosterDelta)
then
begin
try
FOnDeltaRecordUpdate := UpdatePosterDelta;
dspUpdate
.
ApplyUpdates(PosterDelta,
0
, ErrorCount);
Result := (ErrorCount =
0
);
finally
FOnDeltaRecordUpdate :=
nil
;
end
;
end
;
end
;
|
当dspUpdate的BeforeUpdateRecord事件被触发时,调用UpdatePosterDelta方法,以实现手动更新Delta包的目的:
1
2
3
4
5
6
7
|
procedure
TMoviesMethods
.
dspUpdateBeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet; DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;
var
Applied:
Boolean
);
begin
if
Assigned(FOnDeltaRecordUpdate)
then
FOnDeltaRecordUpdate(Sender, SourceDS, DeltaDS, UpdateKind, Applied);
end
;
|
UpdatePosterDelta方法。这里使用了一个TSQLDataSet控件dsQuery,利用它来提交SQL语句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
procedure
TMoviesMethods
.
UpdatePosterDelta(Sender: TObject; SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;
var
Applied:
Boolean
);
begin
Applied :=
False
;
case
UpdateKind
of
ukModify:
begin
with
dsQuery
do
begin
Close;
CommandText :=
'update poster set picture=:picture '
+
'where film_id=:film_id'
;
ParamByName(
'film_id'
).AsInteger := DeltaDS
.
FieldByName(
'film_id'
).OldValue;
ParamByName(
'picture'
).AsBlob := DeltaDS
.
FieldByName(
'picture'
).AsBytes;
if
ExecSQL() =
0
then
Abort;
end
;
end
;
ukInsert:
begin
with
dsQuery
do
begin
Close;
CommandText :=
'insert into poster(film_id, picture) '
+
'values(:film_id, :picture)'
;
ParamByName(
'film_id'
).AsInteger := DeltaDS
.
FieldByName(
'film_id'
).AsInteger;
ParamByName(
'picture'
).AsBlob := DeltaDS
.
FieldByName(
'picture'
).AsBytes;
if
ExecSQL() =
0
then
Abort;
end
;
end
;
ukDelete:
begin
with
dsQuery
do
begin
Close;
CommandText :=
'delete poster '
+
'where film_id=:film_id'
;
ParamByName(
'film_id'
).AsInteger := DeltaDS
.
FieldByName(
'film_id'
).OldValue;
if
ExecSQL() =
0
then
Abort;
end
;
end
;
end
;
Applied :=
True
;
end
;
|
本文地址:http://www.7down.net/article/36894.html
Delphi DataSnap方法实现BLOB字段的读写由第7下载整理并发布,欢迎转载!