[QMacros] 利用模板生成数据库插入语句

QMacros 做为一个模板替换库,拥有良好的属性。结合合适的策略,可以很好的完成复杂的功能。

我们下面的这个例子,试图基于 QMacros 模板生成一个SQL批量插入脚本,首先我们来看下模板定义:

insert into mytable(Id,Name,Age,Sex,Scale,Comment) values ([Id.Quoted],[Name.Quoted],[Age],[Sex],[Scale],[Comment.Quoted]);

这个是我们生成一个简单 SQL 的模板定义,模板中宏以 ‘[‘ 开始,以 ‘]’ 结束,如果一个字段加入 .Quoted 代表这个字段的值要被替换为用单引号引起来的字符串。

好了,我们先看一下这个执行宏替换的效果:

QMacro_Single

嗯,看起来效果不错,可是只有一次记录,如果我们要批量生成所有记录的SQL语句我们怎么办?我们在 QMacro 的一个演示程序中,利用了 OnMissedMacro 事件来做了一个动态的宏处理。这里我们的测试环境是 XE7,使用了它的匿名函数版本,先直接上代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  AMacros: TQMacroManager;
begin
AMacros := TQMacroManager.Create;
AMacros.BooleanAsInt := True;
FDataSet.DisableControls;
Memo1.Lines.BeginUpdate;
try
  Memo1.Lines.Clear;
  AMacros.Push(FDataSet, '');
  AMacros.SetOnMacroMiss(
    procedure(ASender: TQMacroManager; AName: QStringW; const AQuoter: QCharW;
      var AHandled: Boolean)
    begin
    AHandled := StartWithW(PQCharW(AName), 'Repeat:', True);
    if AHandled then
      ASender.Push(AName,
        procedure(AMacro: TQMacroItem; const AQuoter: QCharW)
        var
          AReplace: TQMacroComplied;
          AHelper: TQStringCatHelperW;
        begin
        AReplace := AMacros.Complie(DequotedStrW(Copy(AMacro.Name, 8, MaxInt),
          '"'), '[', ']');
        if Assigned(AReplace) then
          begin
          AHelper := TQStringCatHelperW.Create;
          try
            FDataSet.First;
            while not FDataSet.Eof do
              begin
              AHelper.Cat(AReplace.Replace).Cat(SLineBreak);
              FDataSet.Next;
              end;
            AMacro.Value.Value := AHelper.Value;
          finally
            FreeAndNil(AHelper);
            FreeAndNil(AReplace);
          end;
          end;
        end);
    end);
  Memo1.Lines.Text := AMacros.Replace(edtExp.Text, '[', ']');
finally
  Memo1.Lines.EndUpdate;
  FreeAndNil(AMacros);
  FDataSet.EnableControls;
end;
end;

首先,我们约定了一个格式,如果宏以 “Repeat:” 打头,则认为是重复数据集中的所有记录,这个宏后面实际替换的模板以双引号包起来,以避免直接每一次解析时就被解析到,下面是上面的改良的模板:

[Repeat:"insert into mytable(Id,Name,Age,Sex,Scale,Comment) values ([Id.Quoted],[Name.Quoted],[Age],[Sex],[Scale],[Comment.Quoted]);"]

好了,我们下面回过来看上面贴的代码:

  • AMacros.SetOnMacroMiss 在处理函数中检查未找到的宏是否以 “Repeat:” 打头
    •  如果不是,则直接返回,程序会报告无法找到指定的宏定义;
    • 反过来,如果找到了,则Push这个宏对应的解析函数,而这个解析函数我们为了直观一些,也直接做成了匿名函数
  • 以 Repeat 打头的宏的解析函数做以一系列处理:
    • 将 Repeat 宏名称中,引用中的内容去除引号,得到的原始内容进行编译;
    • 循环数据集,对每一条记录执行一次替换并将替换结果拼接到一起,做为这个宏的值返回;

经过上面的处理,这个宏就完成了循环处理,生成了整个SQL脚本,我们看实际执行的效果:

SQLGEN

滚动至顶部