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 ---------

  • 相关阅读:
    SharePoint 2013 安装.NET Framework 3.5 报错
    SharePoint 2016 配置工作流环境
    SharePoint 2016 站点注册工作流服务报错
    Work Management Service application in SharePoint 2016
    SharePoint 2016 安装 Cumulative Update for Service Bus 1.0 (KB2799752)报错
    SharePoint 2016 工作流报错“没有适用于此应用程序的地址”
    SharePoint 2016 工作流报错“未安装应用程序管理共享服务代理”
    SharePoint JavaScript API in application pages
    SharePoint 2016 每天预热脚本介绍
    SharePoint 无法删除搜索服务应用程序
  • 原文地址:https://www.cnblogs.com/shadow-abyss/p/11126900.html
Copyright © 2011-2022 走看看