zoukankan      html  css  js  c++  java
  • delphi 参数化sql

    曾经查过资料,后来忘了,现在做一下记录。

    ---------

    在 sql 语句里占位使用 一个冒号和一个用来表示这个位置的符号, 例如:SELECT * FROM aTableName WHERE aCol =  :ColVal

    SELECT * FROM aTableName WHERE aCol =  :ColVal

    对占位了的地方赋值这里使用的是 paremeters 属性的 paramByName 作的, 例如:

    LDataSet.Parameters.ParamByName('ColVal').Value := 'SomeValue';

    ---------

    最近在 Delphi 7 中通过参数化的方式存汉字字符串,出现只存入了一部分的情况,搜索资料并测试之后,发现设置 DataType = ftWideString 可以解决。

    示例:

    LCommand.Parameters.ParamByName('AKeyName').DataType := ftWideString;
    LCommand.Parameters.ParamByName('AKeyName').Value := '我没有,我不是,别瞎说';

    DataType 的类型:DB.pas/TFieldType

    --date=2019-08-16

    ---------

    为了使贴出来的代码具有完成性和尽量的简单性, 把以前的代码改写了一下, 现在的代码是控制台程序,

    在程序体中对数据库访问代码作了简单的调用.

    ---------

    今天重新看了一遍代码,发现一个问题,就是 程序入口里的变量 QueryResult 所使用过的对象都没有释放!!!

    --date=2019-09-11

    ---------

    数据访问单元的代码:

      1 unit uDBAccesser;
      2 
      3 interface
      4 
      5 uses
      6   System.Generics.Collections, Data.Win.ADODB;
      7 
      8 
      9 type TTAbleInfo = record
     10   DataSource : String;
     11   DbName     : String;
     12   Username   : String;
     13   Password   : String;
     14   Name       : String;
     15   IntCol     : String;
     16   TxtCol     : String;
     17 end;
     18 
     19 type TEntity = record
     20   SomeInt : Integer;
     21   SomeTxt : String;
     22 end;
     23 
     24 type TDBAccesser = class
     25   private
     26     FConn : TADOConnection;
     27 
     28     function Query( const ASql : String; const AParams : TDictionary<String, Variant>) : TList<TEntity>;
     29     // 广泛含义的更新
     30     function Update(Const ASql : String; const AParams : TDictionary<String, Variant>) : Boolean; overload;
     31   public
     32     constructor Create();
     33     destructor  Destroy(); override;
     34 
     35     function QueryAll() : TList<TEntity>;
     36     function QueryByInt(const AInt : Integer) : TList<TEntity>;
     37     function QueryByTxt(const ATxt : String ) : TList<TEntity>;
     38     function InsertOne(const AEntity : TEntity) : Boolean;
     39     function Delete(const AEntity : TEntity) : Boolean;
     40     // 狭义的更新
     41     function Update(const AOldValue : TEntity; const ANewValue : TEntity) : Boolean; overload;
     42 end;
     43 
     44 
     45 var
     46   TableInfo : TTableInfo;
     47 
     48 implementation
     49 
     50 uses
     51   System.SysUtils, System.Variants, Winapi.ActiveX;
     52 
     53 
     54 constructor TDBAccesser.Create();
     55 const  // MS SQL
     56   LConnStrFormat : String = 'provider=SQLOLEDB.1;password=%s;User ID=%s;'
     57                           + 'Initial CataLog=%s;Data source=%s;';
     58 var
     59   LConnStr : String;
     60 begin
     61   try
     62     LConnStr := Format(LConnStrFormat, [TableInfo.Password, TableInfo.Username,
     63                                         TableInfo.DbName, TableInfo.DataSource]);
     64 
     65     Self.FConn := TADOConnection.Create(nil);
     66     Self.FConn.ConnectionString := LConnStr;
     67     Self.FConn.LoginPrompt := False;
     68     Self.FConn.Connected   := True;
     69   except
     70     on Err : Exception do begin
     71       FreeAndNil(Self.FConn);
     72       WriteLn('Error on create DBAccesser: ' + Err.Message);
     73     end;
     74   end;
     75 end;
     76 
     77 destructor TDBAccesser.Destroy;
     78 begin
     79   FreeAndNil(Self.FConn);
     80 end;
     81 
     82 
     83 function TDBAccesser.Query(const ASql: string; const AParams: TDictionary<System.string,System.Variant>) : TList<TEntity>;
     84 var
     85   LDataSet : TADODataSet;
     86   LRow : TEntity;
     87   LKey : String;
     88 begin
     89   LDataSet := nil;
     90   try
     91     LDataSet := TADODataSet.Create(nil);
     92     LDataSet.Connection  := Self.FConn;
     93     LDataSet.CommandText := ASql;
     94 
     95     // 我印象有篇文章说这句必须要有, 但不写也没发现问题
     96     LDataSet.Parameters.ParseSQL(LDataSet.CommandText, True);
     97     if (AParams <> nil) then begin
     98       for LKey in AParams.Keys do begin
     99         LDataSet.Parameters.ParamByName(LKey).Value := AParams.Items[LKey];
    100       end;
    101     end;
    102 
    103     LDataSet.Open;
    104     LDataSet.First;
    105 
    106     Result := TList<TEntity>.Create();
    107     while not LDataSet.Eof do begin
    108       LRow.SomeInt := LDataSet.FieldByName(TableInfo.IntCol).AsInteger; // 也可以这种格式 LDataSet.Fields[0].AsBoolean;
    109       LRow.SomeTxt := LDataSet.FieldByName(TableInfo.TxtCol).AsString;
    110 
    111       Result.Add(LRow);
    112 
    113       LDataSet.Next;
    114     end;
    115   finally
    116     FreeAndNil(LDataSet);
    117   end;
    118 end;
    119 
    120 function TDBAccesser.Update(Const ASql : String; const AParams : TDictionary<String, Variant>) : Boolean;
    121 var
    122   LCmd : TADOCommand;
    123   LKey : String;
    124   LRowsAffected : Integer;
    125 begin
    126   Result := False;
    127   LCmd := nil;
    128   try
    129     LCmd := TADOCommand.Create(nil);
    130     LCmd.Connection  := Self.FConn;
    131     LCmd.CommandText := ASql;
    132 
    133     LCmd.Parameters.ParseSQL(LCmd.CommandText, True);
    134 
    135     if (AParams <> nil) then begin
    136       for LKey in AParams.Keys do begin
    137         LCmd.Parameters.ParamByName(LKey).Value := AParams.Items[LKey];
    138       end;
    139     end;
    140 
    141     // 也可以直接在 EmptyParam 的位置直接写 [Param1, Param2, ...] 格式的内容,
    142     // 而不使用上面的 Parameters,两者不能同时使用,
    143     // 但具体什么情况我也忘了,相应代码也找不到了,要想知道真实情况,还得再动手去摸索
    144     LCmd.Execute(LRowsAffected, EmptyParam);
    145 
    146     if (LRowsAffected > 0) then begin
    147       Result := True;
    148     end
    149     else begin
    150       Result := False;
    151     end;
    152   finally
    153     FreeAndNil(LCmd);
    154   end;
    155 end;
    156 
    157 
    158 function TDBAccesser.QueryAll() : TList<TEntity>;
    159 const
    160   LSqlFormat : String = 'SELECT %s, %s FROM %s';
    161 var
    162   LSql : String;
    163 begin
    164   LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol, TableInfo.Name]);
    165 
    166   Result := Self.Query(LSql, nil);
    167 end;
    168 
    169 function TDBAccesser.QueryByInt(const AInt: Integer) : TList<TEntity>;
    170 const
    171   LSqlFormat : String = 'SELECT %s, %s FROM %s WHERE %s = :$Int ';
    172 var
    173   LSql : String;
    174   LParams : TDictionary<String, Variant>;
    175 begin
    176   LParams := TDictionary<String, Variant>.Create();
    177   try
    178     LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol,
    179                                 TableInfo.Name, TableInfo.IntCol]);
    180 
    181     LParams.Add('$Int', AInt);
    182 
    183     Result := Self.Query(LSql, LParams);
    184   finally
    185     FreeAndNil(LParams);
    186   end;
    187 end;
    188 
    189 function TDBAccesser.QueryByTxt(const ATxt: String) : TList<TEntity>;
    190 const
    191   LSqlFormat : String = 'SELECT %s, %s FROM %s WHERE %s = :$Txt ';
    192 var
    193   LSql : String;
    194   LParams : TDictionary<String, Variant>;
    195 begin
    196   LParams := TDictionary<String, Variant>.Create();
    197   try
    198     LSql := Format(LSqlFormat, [TableInfo.TxtCol, TableInfo.IntCol,
    199                                 TableInfo.Name, TableInfo.TxtCol]);
    200 
    201     LParams.Add('$Txt', ATxt);
    202 
    203     Result := Self.Query(LSql, LParams);
    204   finally
    205     FreeAndNil(LParams);
    206   end;
    207 end;
    208 
    209 function TDBAccesser.InsertOne(const AEntity: TEntity) : Boolean;
    210 const
    211   LSqlFormat : String = 'INSERT INTO %s (%s, %s) '
    212                       + 'VALUES (:$Txt, :$Int) ';
    213 var
    214   LSql : String;
    215   LParams : TDictionary<String, Variant>;
    216 begin
    217   LParams := TDictionary<String, Variant>.Create();
    218   try
    219     LSql := Format(LSqlFormat, [TableInfo.Name, TableInfo.TxtCol, TableInfo.IntCol]);
    220 
    221     LParams.Add('$Txt', AEntity.SomeTxt);
    222     LParams.Add('$Int', AEntity.SomeInt);
    223 
    224     Result := Self.Update(LSql, LParams);
    225   finally
    226     FreeAndNil(LParams);
    227   end;
    228 end;
    229 
    230 function TDBAccesser.Delete(const AEntity: TEntity) : Boolean;
    231 const
    232   LSqlFormat : String = 'DELETE FROM %s '
    233                       + 'WHERE %s = :$Txt AND %s = :$Int ';
    234 var
    235   LSql : String;
    236   LParams : TDictionary<String, Variant>;
    237 begin
    238   LParams := TDictionary<String, Variant>.Create();
    239   try
    240     LSql := Format(LSqlFormat, [TableInfo.Name, TableInfo.TxtCol, TableInfo.IntCol]);
    241 
    242     LParams.Add('$Txt', AEntity.SomeTxt);
    243     LParams.Add('$Int', AEntity.SomeInt);
    244 
    245     Result := Self.Update(LSql, LParams);
    246   finally
    247     FreeAndNil(LParams);
    248   end;
    249 end;
    250 
    251 function TDBAccesser.Update(const AOldValue: TEntity; const ANewValue: TEntity) : Boolean;
    252 const
    253   LSqlFormat : String = 'UPDATE %s '
    254                       + 'SET %s = :$TxtVal, %s = :$IntVal '
    255                       + 'WHERE %s = :$OldTxtVal AND %s = :$OldIntVal ';
    256 var
    257   LSql : String;
    258   LParams : TDictionary<String, Variant>;
    259 begin
    260   LParams := TDictionary<String, Variant>.Create();
    261   try
    262     LSql := Format(LSqlFormat, [TableInfo.Name,
    263                                 TableInfo.TxtCol, TableInfo.IntCol,
    264                                 TableInfo.TxtCol, TableInfo.IntCol]);
    265 
    266     LParams.Add('$TxtVal', ANewValue.SomeTxt);
    267     LParams.Add('$IntVal', ANewValue.SomeInt);
    268 
    269     LParams.Add('$OldTxtVal', AOldValue.SomeTxt);
    270     LParams.Add('$OldIntVal', AOldValue.SomeInt);
    271 
    272     Result := Self.Update(LSql, LParams);
    273   finally
    274     FreeAndNil(LParams);
    275   end;
    276 end;
    277 
    278 
    279 initialization
    280   TableInfo.DataSource := '.';
    281   TableInfo.DbName     := 'simpleTestByX';
    282   TableInfo.Username   := 'sa';
    283   TableInfo.Password   := '123456';
    284   TableInfo.Name       := 'tab_simple_test';
    285   TableInfo.IntCol     := 'some_int';
    286   TableInfo.TxtCol     := 'some_txt';
    287 
    288   CoInitialize(nil);
    289 
    290 finalization
    291   CoUninitialize();
    292 
    293 
    294 end.

    控制台程序入口代码,对上面的单元进行简单的调用:

      1 program ProjectParameterizedSql;
      2 
      3 {$APPTYPE CONSOLE}
      4 
      5 {$R *.res}
      6 
      7 uses
      8   System.SysUtils,
      9   System.Generics.Collections,
     10   uDBAccesser in 'uDBAccesser.pas';
     11 
     12 
     13 function FormatEntity(AEntity : TEntity) : String;
     14 begin
     15   Result := Format(' SomeInt = %d, SomeTxt = %s ', [AEntity.SomeInt, AEntity.SomeTxt]);
     16 end;
     17 
     18 
     19 var
     20   DBAccesser      : TDBAccesser;
     21   EntityQuery     : TEntity;
     22   EntityInsert    : TEntity;
     23   EntityDelete    : TEntity;
     24   EntityUpdateNew : TEntity;
     25   EntityUpdateOld : TEntity;
     26   EntityCommon    : TEntity;
     27   QueryResult     : TList<TEntity>;
     28 begin
     29   try
     30     DBAccesser := TDBAccesser.Create();
     31     try
     32       WriteLn('1) insert one: ');
     33 
     34       EntityInsert.SomeInt := 1;
     35       EntityInsert.SomeTxt := 'Hello';
     36       WriteLn('  entity = ', FormatEntity(EntityInsert));
     37 
     38       WriteLn('  insert success? ', DBAccesser.InsertOne(EntityInsert));
     39       WriteLn('----------------');
     40 
     41       WriteLn('2) query all: ');
     42 
     43       QueryResult := DBAccesser.QueryAll();
     44 
     45       WriteLn('  total = ', QueryResult.Count);
     46       for EntityCommon in QueryResult do begin
     47         WriteLn('  ', FormatEntity(EntityCommon));
     48       end;
     49       WriteLn('----------------');
     50 
     51       WriteLn('3) update: ');
     52 
     53       EntityUpdateOld := EntityInsert;
     54       EntityUpdateNew.SomeInt := 2;
     55       EntityUpdateNew.SomeTxt := 'World';
     56 
     57       WriteLn('  old : ', FormatEntity(EntityUpdateOld));
     58       WriteLn('  new : ', FormatEntity(EntityUpdateNew));
     59 
     60       WriteLn('  update success? ', DBAccesser.Update(EntityUpdateOld, EntityUpdateNew));
     61       WriteLn('----------------');
     62 
     63       WriteLn('4) query by int:');
     64 
     65       EntityQuery := EntityUpdateNew;
     66       WriteLn('  int = ', EntityQuery.SomeInt);
     67 
     68       QueryResult := DBAccesser.QueryByInt(EntityQuery.SomeInt);
     69 
     70       WriteLn('  total : ', QueryResult.Count);
     71       for EntityCommon in QueryResult do begin
     72         WriteLn('  ', FormatEntity(EntityCommon));
     73       end;
     74       WriteLn('----------------');
     75 
     76       WriteLn('5) query by txt:');
     77 
     78       EntityQuery := EntityUpdateNew;
     79       WriteLn('  txt = ', EntityQuery.SomeTxt);
     80 
     81       QueryResult := DBAccesser.QueryByTxt(EntityQuery.SomeTxt);
     82 
     83       WriteLn('  total : ', QueryResult.Count);
     84       for EntityCommon in QueryResult do begin
     85         WriteLn('  ', FormatEntity(EntityCommon));
     86       end;
     87       WriteLn('----------------');
     88 
     89       WriteLn('6) delete:');
     90 
     91       EntityDelete := EntityUpdateNew;
     92       WriteLn('  entity = ', FormatEntity(EntityDelete));
     93 
     94       WriteLn('  delete success? ', DBAccesser.Delete(EntityDelete));
     95       WriteLn('----------------');
     96 
     97       WriteLn('7) query all: ');
     98 
     99       QueryResult := DBAccesser.QueryAll();
    100       WriteLn('  total : ', QueryResult.Count);
    101       for EntityCommon in QueryResult do begin
    102         WriteLn('  ', FormatEntity(EntityCommon));
    103       end;
    104       WriteLn('----------------');
    105 
    106       WriteLn('--- THE END ---');
    107     finally
    108       FreeAndNil(DBAccesser);
    109     end;
    110   except
    111     on E: Exception do
    112       Writeln(E.ClassName, ': ', E.Message);
    113   end;
    114   ReadLn;
    115 end.

    --------- THE END ---------

  • 相关阅读:
    “Hello World”团队第一周博客汇总
    SFTP服务器之创建普通用户
    软工2017第五周——个人PSP
    "Hello world!"团队第一次会议
    软工2017第四周作业--结对编程之四则运算
    软工2017第四周作业结对编程——个人psp
    软工2017第四周作业结对编程——单元测试
    软工2017第四周作业——代码规范
    软工第三次作业——个人PSP
    iOS原生和React-Native之间的交互1
  • 原文地址:https://www.cnblogs.com/shadow-abyss/p/11126900.html
Copyright © 2011-2022 走看看