delphi ORM和泛型模板

delphi中间件發表於2024-03-30

delphi ORM和泛型模板

1)定義資料模型(data-model)

資料模型是ORM資料序列/還原所必需的。

  TTable<T: record> = record      //1個表
    rows: TArray<T>;              //表的行
  end;

  TTable2<T, T2: record> = record  //2個表
    table1: TTable<T>;             //表1
    table2: TTable<T2>;            //表2
  end;

  TTable3<T, T2, T3: record> = record  //3個表
    table1: TTable<T>;                 //表1
    table2: TTable<T2>;                //表2
    table3: TTable<T3>;                //表3
  end;

 2)實現ORM CRUD泛型模板

/// <author>cxg 2024-3-30</author>
unit db.crud;

interface

uses
  Data.DB,
  System.Classes, System.SysUtils, serialize, yn.log, db.unidacpool, db.unidac,
  global;

type
  TCRUD<T: record> = record  //1個表
    dbid: string;
    func: string;
    sql: string;
    db: TDB;
    table: TTable<T>;
    req: TRequest;
    res: TResponse;
    type
      TTableModel = reference to procedure(db: TDB; table: TTable<T>; i: integer);
    procedure open(OnTableModel: TTableModel);  //查詢
    procedure execsql(OnTableModel: TTableModel);  //執行事務性SQL
  end;

  TCRUD2<T, T2: record> = record   //2個表
    dbid: string;
    func: string;
    sqls: array of string;
    db: TDB;
    tables: TTable2<T, T2>;
    req: TRequest;
    res: TResponse;
    type
      TTableModel2 = reference to procedure(db: TDB; tables: TTable2<T, T2>; i: integer);
    procedure open(OnTableModel, OnTableModel2: TTableModel2);  //查詢
    procedure execsql(OnTableModel, OnTableModel2: TTableModel2);  //執行事務性SQL
  end;

implementation

{ TCRUD<T> }

procedure TCRUD<T>.execsql(OnTableModel: TTableModel);
//執行事務性SQL
begin
  if req.Body = nil then
    Exit;
  var pool: TDBPool := GetDBPool(dbid);  //database pool
  db := pool.Lock;
  try
    try
      table := serialize.TSerial<TTable<T>>.unjson(TStream(req.Body));  //json string--->record
      db.startTrans;                //開啟事務
      for var i: Integer := 0 to High(table.rows) do
      begin
        db.qry.Close;
        db.qry.SQL.Clear;
        db.qry.sql.add(sql);
        OnTableModel(db, table, i);  //set field value
        db.qry.ExecSQL;
      end;
      db.commitTrans;         //提交事務
      res.Send(success);
    except
      on E: Exception do
      begin
        db.rollbackTrans;     //回滾事務
        res.Send(error(E.Message));
        WriteLog(func + E.Message);
      end;
    end;
  finally
    pool.Unlock(db);
  end;
end;

procedure TCRUD<T>.open(OnTableModel: TTableModel);
//查詢
begin
  var pool: TDBPool := GetDBPool(dbid);
  db := pool.Lock;
  try
    try
      var where: string;              //where條件
      if req.Body <> nil then
        where := TEncoding.UTF8.GetString(TBytesStream(req.Body).Bytes);
      var lsql: string;
      if where = '' then             //拼SQL查詢命令
        lsql := sql
      else
        lsql := sql + ' where ' + where;
      db.select(lsql);       //查詢
      SetLength(table.rows, db.qry.RecordCount);    //記錄條數
      var i: Integer := 0;
      db.qry.First;                    //dataset--->record
      while not db.qry.Eof do
      begin
        OnTableModel(db, table, i);    //set field value
        db.qry.Next;
        Inc(i);
      end;
      res.Send(TSerial<TTable<T>>.json(table));   //send json string
    except
      on E: Exception do
      begin
        res.Send(error(E.Message));
        writelog(func + E.Message);
      end;
    end;
  finally
    pool.Unlock(db);
  end;
end;

{ TCRUD2<T, T2> }

procedure TCRUD2<T, T2>.execsql(OnTableModel, OnTableModel2: TTableModel2);
//2個表執行事務性SQL
begin
  if req.Body = nil then
    Exit;
  var pool: TDBPool := GetDBPool(dbid);  //database pool
  db := pool.Lock;
  try
    try
      tables := serialize.TSerial<TTable2<T, T2>>.unjson(TStream(req.Body));  //json string--->record
      db.startTrans;      //開啟事務
      for var i: Integer := 0 to High(tables.table1.rows) do  //遍歷table1 record
      begin
        db.qry.Close;
        db.qry.SQL.Clear;
        db.qry.sql.add(sqls[0]);
        OnTableModel(db, tables, i);    //set field value
        db.qry.ExecSQL;
      end;
      for var i: Integer := 0 to High(tables.table2.rows) do   //遍歷table2 record
      begin
        db.qry.Close;
        db.qry.SQL.Clear;
        db.qry.sql.add(sqls[1]);
        OnTableModel2(db, tables, i);  //set field value
        db.qry.ExecSQL;
      end;
      db.commitTrans;     //提交事務
      res.Send(success);
    except
      on E: Exception do
      begin
        db.rollbackTrans;   //回滾事務
        res.Send(error(E.Message));
        WriteLog(func + E.Message);
      end;
    end;
  finally
    pool.Unlock(db);
  end;
end;

procedure TCRUD2<T, T2>.open(OnTableModel, OnTableModel2: TTableModel2);
//2個表查詢
begin
  var pool: TDBPool := GetDBPool(dbid);   //database pool
  db := pool.Lock;
  try
    try
      db.select(sqls[0]);    //table1 查詢
      SetLength(tables.table1.rows, db.qry.RecordCount);    //記錄條數
      var i: Integer := 0;
      db.qry.First;
      while not db.qry.Eof do
      begin
        OnTableModel(db, tables, i);   //set field value
        db.qry.Next;
        Inc(i);
      end;
      db.select(sqls[1]);     //table2 查詢
      SetLength(tables.table2.rows, db.qry.RecordCount);  //記錄條數
      i := 0;
      db.qry.First;
      while not db.qry.Eof do
      begin
        OnTableModel2(db, tables, i);   //set field value
        db.qry.Next;
        Inc(i);
      end;
      res.Send(TSerial<TTable2<T, T2>>.json(tables));  //send json string
    except
      on E: Exception do
      begin
        res.Send(error(E.Message));
        writelog(func + E.Message);
      end;
    end;
  finally
    pool.Unlock(db);
  end;
end;

end.

 3)透過CRUD泛型模板實現資源(resource)資料操作

3.1)單表的

unit danwei;
/// <author>cxg 2024-1-21</author>

interface

uses
  db.crud, yn.log, danwei.model, global,
  db.unidac, system.Classes, serialize, System.SysUtils;

type
  TRESTdanwei = class(Trpc)  //單位的遠端方法類
    procedure select(const req: TRequest; const res: TResponse);  //查詢
    procedure insert(const req: TRequest; const res: TResponse);  //新增
    procedure update(const req: TRequest; const res: TResponse);  //修改
    procedure delete(const req: TRequest; const res: TResponse);  //刪除
  end;

implementation

procedure TRESTdanwei.select(const req: TRequest; const res: TResponse);
//查詢
begin
  var crud: TCRUD<Tdanwei>;
  crud.dbid := '1';
  crud.func := 'TRESTdanwei.select()';
  crud.req := req;
  crud.res := res;
  crud.sql := 'select * from tunit';
  crud.open(
    procedure(db: TDB; table: TTable<Tdanwei>; i: Integer)
    begin
      table.rows[i].unitid := db.qry.FieldByName('unitid').AsString;//dataset-->model
      table.rows[i].unitname := db.qry.FieldByName('unitname').AsString;
    end);
end;

procedure TRESTdanwei.delete(const req: TRequest; const res: TResponse);
//刪除
begin
  var crud: TCRUD<Tdanwei>;
  crud.dbid := '1';
  crud.func := 'TRESTdanwei.delete()';
  crud.req := req;
  crud.res := res;
  crud.sql := 'delete from tunit where unitid=:unitid';
  crud.execsql(
    procedure(db: TDB; table: TTable<Tdanwei>; i: Integer)
    begin
      db.qry.ParamByName('unitid').AsString := table.rows[i].unitid;
    end);
end;

procedure TRESTdanwei.insert(const req: TRequest; const res: TResponse);
//新增
begin
  var crud: TCRUD<Tdanwei>;
  crud.dbid := '1';
  crud.func := 'TRESTdanwei.insert()';
  crud.req := req;
  crud.res := res;
  crud.sql := 'insert into tunit(unitid,unitname) values (:unitid,:unitname)';
  crud.execsql(
    procedure(db: TDB; table: TTable<Tdanwei>; i: Integer)
    begin
      db.qry.ParamByName('unitid').AsString := table.rows[i].unitid;
      db.qry.ParamByName('unitname').AsString := table.rows[i].unitname;
    end);
end;

procedure TRESTdanwei.update(const req: TRequest; const res: TResponse);
//修改
begin
  var crud: TCRUD<Tdanwei>;
  crud.dbid := '1';
  crud.func := 'TRESTdanwei.update()';
  crud.req := req;
  crud.res := res;
  crud.sql := 'update tunit set unitid=:unitid,unitname=:unitname where unitid=:key';
  crud.execsql(
    procedure(db: TDB; table: TTable<Tdanwei>; i: Integer)
    begin
      db.qry.ParamByName('unitid').AsString := table.rows[i].unitid;
      db.qry.ParamByName('unitname').AsString := table.rows[i].unitname;
      db.qry.ParamByName('key').AsString := table.rows[i].unitid;
    end);
end;

initialization
  RegisterClass(TRESTdanwei);

finalization
  UnRegisterClass(TRESTdanwei);

end.

  3.2)多表的

unit tables ;
/// <author>cxg 2024-1-21</author>
/// 多表演示
interface

uses
  db.crud, yn.log, danwei.model, product.model, global,
  db.unidac, system.Classes, serialize, System.SysUtils;

type
  TRESTtables = class(Trpc)  //單位的遠端方法類
    procedure select(const req: TRequest; const res: TResponse);  //查詢
    procedure insert(const req: TRequest; const res: TResponse);  //新增
    procedure update(const req: TRequest; const res: TResponse);  //修改
    procedure delete(const req: TRequest; const res: TResponse);  //刪除
  end;

implementation

procedure TRESTtables.select(const req: TRequest; const res: TResponse);
//多表查詢
begin
  var crud: TCRUD2<Tdanwei, Tproduct>;
  crud.dbid := '1';
  crud.func := 'TRESTtables.select()';
  crud.req := req;
  crud.res := res;
  var sql1: string := 'select top 2 * from tunit';
  var sql2: string := 'select top 2 * from tgoods';
  crud.sqls := [sql1, sql2];
  crud.open(
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      tables.table1.rows[i].unitid := db.qry.FieldByName('unitid').AsString;//dataset-->model
      tables.table1.rows[i].unitname := db.qry.FieldByName('unitname').AsString;
    end,
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      tables.table2.rows[i].goodsid := db.qry.FieldByName('goodsid').AsString;//dataset-->model
      tables.table2.rows[i].jj := db.qry.FieldByName('jj').AsFloat;
    end);
end;

procedure TRESTtables.delete(const req: TRequest; const res: TResponse);
//多表刪除
begin
  var crud: TCRUD2<Tdanwei, Tproduct>;
  crud.dbid := '1';
  crud.func := 'TRESTtables.delete()';
  crud.req := req;
  crud.res := res;
  var sql1: string := 'delete from tunit where unitid=:unitid';
  var sql2: string := 'delete from tgoods where goodsid=:goodsid';
  crud.sqls := [sql1, sql2];
  crud.execsql(
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('unitid').AsString := tables.table1.rows[i].unitid;
    end,
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('goodsid').AsString := tables.table2.rows[i].goodsid;
    end);
end;

procedure TRESTtables.insert(const req: TRequest; const res: TResponse);
//多表新增
begin
  var crud: TCRUD2<Tdanwei, Tproduct>;
  crud.dbid := '1';
  crud.func := 'TRESTtables.insert()';
  crud.req := req;
  crud.res := res;
  var sql1: string := 'insert into tunit(unitid,unitname) values (:unitid,:unitname)';
  var sql2: string := 'insert into tgoods(goodsid,jj) values (:goodsid,:jj)';
  crud.sqls := [sql1, sql2];
  crud.execsql(
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('unitid').AsString := tables.table1.rows[i].unitid;
      db.qry.ParamByName('unitname').AsString := tables.table1.rows[i].unitname;
    end,
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('goodsid').AsString := tables.table2.rows[i].goodsid;
      db.qry.ParamByName('jj').AsFloat := tables.table2.rows[i].jj;
    end);
end;

procedure TRESTtables.update(const req: TRequest; const res: TResponse);
//多表修改
begin
  var crud: TCRUD2<Tdanwei, Tproduct>;
  crud.dbid := '1';
  crud.func := 'TRESTtables.update()';
  crud.req := req;
  crud.res := res;
  var sql1: string := 'update tunit set unitid=:unitid,unitname=:unitname where unitid=:key';
  var sql2: string := 'update tgoods set goodsid=:goodsid,jj=:jj where goodsid=:key';
  crud.sqls := [sql1, sql2];
  crud.execsql(
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('unitid').AsString := tables.table1.rows[i].unitid;
      db.qry.ParamByName('unitname').AsString := tables.table1.rows[i].unitname;
      db.qry.ParamByName('key').AsString := tables.table1.rows[i].unitid;
    end,
    procedure(db: TDB; tables: TTable2<Tdanwei, Tproduct>; i: integer)
    begin
      db.qry.ParamByName('goodsid').AsString := tables.table2.rows[i].goodsid;
      db.qry.ParamByName('jj').AsFloat := tables.table2.rows[i].jj;
      db.qry.ParamByName('key').AsString := tables.table2.rows[i].goodsid;
    end);
end;

initialization
  RegisterClass(TRESTtables);

finalization
  UnRegisterClass(TRESTtables);

end.

  

 

 

相關文章