如何高效存取SQL Server 2000中BLOB字段 |
答題得分者是:jieshu
|
jmjunta52372937
一般會員 發表:1 回覆:2 積分:0 註冊:2005-04-27 發送簡訊給我 |
在下在开发中碰到一个问题,就是如何高效存取SQL Server 2000中BLOB字段。请各位高手赐教。
问题背景:在开发基于SQL Server 2000的一个传统c/S数据库应用程序时,一个用户表中有多个image(即BLOB)类型的字段(现以三个字段bFacePhoto、bSidePhoto、bAllPhoto来说明问题),用于存放三幅图(JPG格式的,已经过减肥,每幅图大小不等,最小的45KB,最大的100多KB),存取现在都是没有问题的,问题的核心是在取出相应的记录时,有相当的延时。 我用的是开发工具是delphi 7,用ADO访问数据库,现在我想加入ClientDataSet和DataSetProvider,并设置DataSetProvider 的poFetchBlobsOnDemand为True,想利用这个缓冲数据集在解决读取图像时严重延时的问题,我想在列记录时先不取出BLOB信息,等用户想查看图像时,就再读取相应记录的BLob信息,我调用了Fill_Picture(DataSet)过程完成图像读取,代码如下: [code delphi] procedure TFrmNew.Fill_Picture(DataSet: TDataSet); var sFileName1, sFileName2, sFileName3: string; tempstream1, tempstream2, tempstream3: TStringStream; tempjpeg1, tempjpeg2, tempjpeg3: TJPEGImage; begin if not DataSet.IsEmpty then begin try tempstream1 := TStringStream.Create(' '); tempstream2 := TStringStream.Create(' '); tempstream3 := TStringStream.Create(' '); if (not Dataset.FieldByName('bFacePhoto').IsNull) then begin TBlobField(Dataset.FieldByName('bFacePhoto')).SaveToStream(tempstream1); tempstream1.Position := 0; if not Assigned(tempjpeg1) then tempjpeg1 := TJPEGImage.Create; tempjpeg1.LoadFromStream(tempstream1); Img1.Picture.Bitmap.Assign(tempjpeg1); sFileName1 := ExtractFilePath(Application.ExeName) 'tmpFaceBlob'; sFileName1 := sFileName1 '.Jpg'; img1.Picture.SaveToFile(sFileName1); end else begin Img1.Picture.Graphic := nil; //清空正面照图像 end; if (not Dataset.FieldByName('bSidePhoto').IsNull) then begin TBlobField(Dataset.FieldByName('bSidePhoto')).SaveToStream(tempstream2); tempstream2.Position := 0; if not Assigned(tempjpeg2) then tempjpeg2 := TJPEGImage.Create; tempjpeg2.LoadFromStream(tempstream2); Img2.Picture.Bitmap.Assign(tempjpeg2); sFileName2 := ExtractFilePath(Application.ExeName) 'tmpSideBlob'; sFileName2 := sFileName2 '.Jpg'; img2.Picture.SaveToFile(sFileName2); end else begin Img2.Picture.Graphic := nil; //清空侧面照图像 end; if (not Dataset.FieldByName('bAllPhoto').IsNull) then begin TBlobField(Dataset.FieldByName('bAllPhoto')).SaveToStream(tempstream3); tempstream3.Position := 0; if not Assigned(tempjpeg3) then tempjpeg3 := TJPEGImage.Create; tempjpeg3.LoadFromStream(tempstream3); Img3.Picture.Bitmap.Assign(tempjpeg3); sFileName3 := ExtractFilePath(Application.ExeName) 'tmpAllBlob'; sFileName3 := sFileName3 '.Jpg'; img3.Picture.SaveToFile(sFileName3); end else begin Img3.Picture.Graphic := nil; //清空全身照图像 end; OleContainer1.Visible := False; finally if sFileName1 <> '' then deleteFile(sfileName1); if sFileName2 <> '' then deleteFile(sfileName2); if sFileName3 <> '' then deleteFile(sfileName3); if Assigned(tempjpeg1) then tempjpeg1.Free; if Assigned(tempjpeg2) then tempjpeg2.Free; if Assigned(tempjpeg3) then tempjpeg3.Free; tempstream1.Free; tempstream2.Free; tempstream3.Free; end; end; end; [/code] 因此我在ClientDataSet的AfterScroll中: [code delphi] procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet); begin Fill_Picture(DataSet); end; [/code] 但问题出来了,设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,但我想在用户在DBGridEh1中移动光标定位到下一行时就取出图像,其实是不应该在ClientDataSet1AfterScroll中调用Fill_Picture 的,因为这样一旦ClientDataSet1.Open后就会执行Fill_Picture, 如果不在ClientDataSet1AfterScroll中调用Fill_Picture 请问我该如何做?谢谢了。 另ClientDataSet1.FetchBlobs如何用 精通它,才能毁灭它。无知者无畏。
------
精通它,才能毁灭它。无知者无畏。 編輯記錄
GrandRURU 重新編輯於 2016-05-15 19:07:31, 註解 無‧
|
jieshu
版主 發表:42 回覆:894 積分:745 註冊:2002-04-15 發送簡訊給我 |
引言:如果要在User移動光標就取出圖像, 當然就一定要寫在AfterScroll事件, 且只抓一筆的圖檔應該還好, 我用一個簡單的範例(DBDEMOS的animals轉入MS SQL)測試了一下, 在取用前下FetchBlobs即可, 亦可在ClientDataSet上設FetchOnDemand為True就會自動抓取, 不用再下FetchBlobs, 不過一定要有一個Primary Key的Index, 這就是我為什麼要轉入MS SQL的原因. <iFrame src="http://www.coss.com.tw/jieshu/sign.htm" width=400 height=105 scolling="NO" border="0"></iFrame> 震江系統(股)公司: http://www.coss.com.tw/ 捷舒軟體設計坊: http://www.coss.com.tw/jieshu/procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet); begin ClientDataSet1.FetchBlobs; Fill_Picture(DataSet); end;但问题出来了,设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,但我想在用户在DBGridEh1中移动光标定位到下一行时就取出图像,其实是不应该在ClientDataSet1AfterScroll中调用Fill_Picture 的,因为这样一旦ClientDataSet1.Open后就会执行Fill_Picture, 如果不在ClientDataSet1AfterScroll中调用Fill_Picture 请问我该如何做?谢谢了。
------
人生有夢,逐夢而行 人若為善,福雖未至,禍已遠離 人若為惡,禍雖未至,福已遠離 http://www.taconet.com.tw/jieshu/ |
jmjunta52372937
一般會員 發表:1 回覆:2 積分:0 註冊:2005-04-27 發送簡訊給我 |
首先无论如何要谢谢jieshu,但我按所述
procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet);
begin
ClientDataSet1.FetchBlobs;
Fill_Picture(DataSet);
end;
执行出错,经调试跟踪,发现是在 ClientDataSet1.FetchBlobs一句出现错误:
"Record not found or Changed by another User".我确信表只有我一个用户打开。这是在设置DataSetProvider 的poFetchBlobsOnDemand为True情形下试的.原因为何,不得而解,请赐教,谢谢! 精通它,才能毁灭它。无知者无畏。
------
精通它,才能毁灭它。无知者无畏。 |
JustinShen
中階會員 發表:22 回覆:104 積分:80 註冊:2003-09-20 發送簡訊給我 |
引言: 执行出错,经调试跟踪,发现是在 ClientDataSet1.FetchBlobs一句出现错误: "Record not found or Changed by another User".我确信表只有我一个用户打开。这是在设置DataSetProvider 的poFetchBlobsOnDemand为True情形下试的.原因为何,不得而解,请赐教,谢谢!正如Jieshu所言,必须有一个PrimaryKey。但是只有PrimaryKey而没有设置每个字段的ProviderFlags或UpdateMode仍然没有用,执行FetchBlobs时ClientDataSet还是传回了所有字段值来获取Blobs字段,因此失效了。 Justin Shen
------
==================== 我为一切作努力! Justin Shen |
pcplayer99
尊榮會員 發表:146 回覆:790 積分:632 註冊:2003-01-21 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |