久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
    分享

    多層數(shù)據(jù)庫(kù)應(yīng)用基于Delphi DataSnap方法調(diào)用的實(shí)現(xiàn)(四)BLOB字段的讀寫

     A芝蘭之室 2017-10-29
                        

    數(shù)據(jù)庫(kù)的BLOB字段,可以用來(lái)保存字節(jié)流數(shù)據(jù),比如圖片、聲音文件、html文檔和大文本等等。Delphi傳統(tǒng)的DataSnap技術(shù),客戶端數(shù)據(jù)集的數(shù)據(jù)包缺省不包含Blob字段數(shù)據(jù),但可以在真正需要的時(shí)刻,實(shí)時(shí)自動(dòng)從數(shù)據(jù)庫(kù)取得,這種自動(dòng)實(shí)現(xiàn)是基于IAppServer接口的。但在DataSnap 2009中,中間層通過方法調(diào)用返回TDataSet的時(shí)候,客戶端無(wú)法再通過IAppServer接口取得Blob字段數(shù)據(jù)了,因?yàn)檫@是方法調(diào)用方式,沒有IAppServer接口的實(shí)現(xiàn)。要解決客戶端讀取Blob字段數(shù)據(jù)的問題,可以在中間層單獨(dú)申明和定義一個(gè)返回Blob字段數(shù)據(jù)流的方法,客戶端在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用此方法就可以返回Blob字段數(shù)據(jù)了。下面以一個(gè)簡(jiǎn)單例子說(shuō)明整個(gè)讀寫過程的實(shí)現(xiàn)。

    假設(shè)我們有一個(gè)Oracle的Poster表,保存電影的海報(bào)信息。包含兩個(gè)字段:
    Film_id Integer
    Picture BLOB

    中間層返回海報(bào)表中的所有記錄:
    function TMoviesMethods.GetPictures: TDataSet;
    begin
      with dsQuery do
      begin
        Close;
        CommandText := 'select * from poster';
        Open;
      end;
      Result := dsQuery;
    end;

    中間層再定義一個(gè)根據(jù)指定ID返回圖片數(shù)據(jù)流的方法:
    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;


    客戶端用一個(gè)TClientDataSet控件來(lái)接收數(shù)據(jù),用一個(gè)TEdit顯示當(dāng)前記錄的ID,一個(gè)TImage控件顯示當(dāng)前記錄的圖片。當(dāng)TClientDataSet.AfterScroll事件發(fā)生時(shí),填寫TEdit和TImage控件的內(nèi)容,其中,TMoviesMethodsClient是自動(dòng)生成的中間層方法的客戶端代理類:
    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;

     

    接下來(lái),演示客戶端新增一條記錄,為Blob字段添加圖片數(shù)據(jù),并寫回?cái)?shù)據(jù)庫(kù)的過程。


    客戶端新增一條記錄:
    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方法是中間層實(shí)現(xiàn)的一個(gè)方法:
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      with SqlServerMethod1 do
      begin
        ServerMethodName := 'TMoviesMethods.SavePictures';
        ParamByName('PosterDelta').Value := ClientDataSet1.Delta;
        ExecuteMethod;
      end;
    end;

    中間層實(shí)現(xiàn)保存Delta數(shù)據(jù)包的方法。過程中,用到一個(gè)TDataSetProvider控件dspUpdate,利用它來(lái)解析Delta包,生成SQL語(yǔ)句,提交數(shù)據(jù)庫(kù)執(zhí)行;UpdatePosterDelta過程真正實(shí)現(xiàn)手動(dòng)更新Delta包:
    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;

    當(dāng)dspUpdate的BeforeUpdateRecord事件被觸發(fā)時(shí),調(diào)用UpdatePosterDelta方法,以實(shí)現(xiàn)手動(dòng)更新Delta包的目的:
    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方法。這里使用了一個(gè)TSQLDataSet控件dsQuery,利用它來(lái)提交SQL語(yǔ)句:
    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;

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶 評(píng)論公約

      類似文章 更多

      主站蜘蛛池模板: 国产V亚洲V天堂无码久久久| 丝袜美腿一区二区三区| 日产精品一卡2卡三卡四乱码| 无码国产精品久久一区免费| 成人无码午夜在线观看| 国产日韩久久免费影院| 国产又爽又黄无码无遮挡在线观看 | 欧美伦费免费全部午夜最新| 亚洲综合激情另类小说区| 中文字幕精品亚洲二区| 久久精品国产亚洲AV麻豆长发| 久久综合九色欧美综合狠狠| 人人人澡人人肉久久精品| 亚洲AV无码一区二区三区在线播放| 欧美极品色午夜在线视频| 亚洲AV成人无码精品电影在线| 成人无码午夜在线观看| 粗壮挺进邻居人妻| 国产色无码专区在线观看| 色婷婷久久综合中文久久一本 | 在线国产精品中文字幕| 精品国产人妻一区二区三区久久| 伊人久久大香线蕉AV五月天| 亚洲欧美中文日韩V在线观看| 欧美国产日韩A在线观看 | 美乳丰满人妻无码视频| 波多野结AV衣东京热无码专区| 最新国产AV最新国产在钱| 午夜无码片在线观看影院A| 亚洲AV福利天堂在线观看| 2020无码专区人妻系列日韩| 国产曰批视频免费观看完| 国产精品中文字幕二区| 亚洲 欧美 国产 制服 动漫| 亚洲一二区制服无码中字| 国内精品久久久久影院网站| 成人区人妻精品一区二区不卡| 国色天香成人一区二区| 美女禁区a级全片免费观看| 国产精品久久久天天影视香蕉| 野外做受三级视频|