DELPHI开发2层C/S数据库应用程序,许多人通过ADOQUERY或ADOTABLE直接操作数据库,其实这种方法虽然最为直接,但有其缺点:如果以后要将程序升级为3层C/S会非常困难。而通过像下面的通用数据操作方法,像开发3层C/S一样地开发2层C/S程序,通过ADOQUERY或ADOTABLE获取数据,通过DATASETPROVIDER转换数据格式为OLEVARIANT,通过CLIENTDATASET内存数据集再同客户端显示控件关联,则所有操作数据的方法高度集中统一,以后要升级为多层会非常容易。这就是间接所带来的高度灵活。

ADO不能像FIREDAC和UNIDAC一样提交联表查询的CLIENTDATASET.DELTA,这在保存类似“单据”的数据的时候很不方便,需要间接一下然后才能提交。

FIREDAC和UNIDAC虽然默认也不支持,但只要设置属性就能获得支持。

其中FIREDAC的设置:UpdateOptions.CheckReadOnly:=False

其中的原由:A表联接B表查询,CLIENTDATASET中的字段既有A表的也有B表的,试图将CLIENTDATASET.delta提交给A表,CLIENTDATASET.delta将B表的字段值改变也一块打包了,而B表的字段的readonly:=true,试图提交只读字段会报错。

unit untDB;

interface

uses
System.SysUtils, System.Classes, Data.DB, Data.Win.ADODB, Datasnap.Provider,
System.Variants, Vcl.Forms;

type
TfrmDB = class(TDataModule)
ADOConnection1: TADOConnection;
qryQuery: TADOQuery;
DataSetProvider1: TDataSetProvider;
qryExecute: TADOQuery;
procedure DataModuleCreate(Sender: TObject);
procedure qryQueryBeforeOpen(DataSet: TDataSet);
procedure qryQueryAfterOpen(DataSet: TDataSet);
private
{ Private declarations }
procedure connectDB;
public
{ Public declarations }
function querySQL(const sql: string): OleVariant;
function executeSQL(const sql: string): Boolean;
function saveData(const tableName: string; delta: OleVariant): Boolean;
function SaveDatas(tableNames, deltas: OleVariant;
tableCount: Integer): Boolean;
end;

var
frmDB: TfrmDB;

implementation

{ %CLASSGROUP 'Vcl.Controls.TControl' }

uses UnitWait;

{$R *.dfm}
{ TfrmDB }

procedure TfrmDB.connectDB;
begin
ADOConnection1.Close;
ADOConnection1.ConnectionString := 'FILE NAME=' +
ExtractFilePath(Application.ExeName) + 'db.udl';
try
ADOConnection1.Connected := True;
except
on E: Exception do
raise Exception.Create(E.Message);
end;
end;

procedure TfrmDB.DataModuleCreate(Sender: TObject);
begin
connectDB;
end;

function TfrmDB.executeSQL(const sql: string): Boolean;
begin
Result := False;
if sql = '' then
Exit;
qryExecute.Close;
qryExecute.sql.Clear;
qryExecute.sql.Text := sql;
Result := qryExecute.ExecSQL > 0;
end;

procedure TfrmDB.qryQueryAfterOpen(DataSet: TDataSet);
begin
FormWait.Close;
FormWait.Free;
end;

procedure TfrmDB.qryQueryBeforeOpen(DataSet: TDataSet);
begin
FormWait := TFormWait.Create(Application);
FormWait.Show;
FormWait.Update;
end;

function TfrmDB.querySQL(const sql: string): OleVariant;
begin
Result := null;
if sql = '' then
Exit;
qryQuery.Close;
qryQuery.sql.Clear;
qryQuery.sql.Text := sql;
qryQuery.Open;
Result := DataSetProvider1.Data;
end;

function TfrmDB.saveData(const tableName: string; delta: OleVariant): Boolean;
var
errCnt: Integer;
begin
Result := False;
if (tableName = '') or VarIsNull(delta) then
Exit;
qryQuery.Close;
qryQuery.sql.Clear;
qryQuery.sql.Text := 'select * from ' + tableName + ' where 1=2';
qryQuery.Open;
DataSetProvider1.ApplyUpdates(delta, 0, errCnt);
Result := errCnt = 0;
end;

function TfrmDB.SaveDatas(tableNames, deltas: OleVariant;
tableCount: Integer): Boolean;
var
i, errCnt: Integer;
begin
if not ADOConnection1.InTransaction then
ADOConnection1.BeginTrans; // 开启事务
try
for i := 0 to tableCount - 1 do
begin
qryQuery.Close;
qryQuery.sql.Clear;
qryQuery.sql.Text := 'select * from ' + tableNames[i] + ' where 1=2';
qryQuery.Open;
DataSetProvider1.ApplyUpdates(deltas[i], 0, errCnt);
end;
ADOConnection1.CommitTrans; // 提交事务
Result := True;
except
ADOConnection1.RollbackTrans; // 回滚事务
Result := False;
end;
end;

end.

ado通用操作数据单元的更多相关文章

  1. EsayUI + MVC + ADO.NET(工作单元)

    关联的设计 关联本身不是一个模式,但它在领域建模的过程中非常重要,所以需要在探讨各种模式之前,先讨论一下对象之间的关联该如何设计.我觉得对象的关联的设计可以遵循如下的一些原则: 关联尽量少,对象之间的 ...

  2. Delphi项目构成之单元文件PAS

    单元文件是Pascal源文件,扩展名为.pas. 有三种类型的单元文件: 窗体/数据模块和框架的单元文件(form/data module and frame units),一般由Delphi自动生成 ...

  3. MVC+EF 理解和实现仓储模式和工作单元模式

    MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generi ...

  4. 【转】Delphi多线程学习(9):多线程数据库查询(ADO)

    原文:http://www.cnblogs.com/djcsch2001/articles/2382559.html ADO多线程数据库查询通常会出现3个问题: 1.CoInitialize 没有调用 ...

  5. 教程-Delphi多线程数据库查询(ADO)

    ADO多线程数据库查询通常会出现3个问题: 1.CoInitialize 没有调用(CoInitialize was not called):所以,在使用任何dbGo对象前,必须手 调用CoIniti ...

  6. Delphi多线程数据库查询(ADO)

    ADO多线程数据库查询通常会出现3个问题: 1.CoInitialize 没有调用(CoInitialize was not called):所以,在使用任何dbGo对象前,必须手 调用CoIniti ...

  7. ADO多线程数据库总结

    ADO多线程数据库查询通常会出现以下问题: 1.CoInitialize 没有调用(CoInitialize was not called):所以,在使用任何dbGo对象前,必须手 调用CoIniti ...

  8. 多线程数据库查询(ADO)

    ADO多线程数据库查询通常会出现3个问题: 1.CoInitialize 没有调用(CoInitialize was not called):所以,在使用任何dbGo对象前,必须手 调用CoIniti ...

  9. ADO多线程数据库查询

    {ADO查询多线程单元} unit ADOThread; interface uses Classes,StdCtrls,ADODB; type TADOThread = class(TThread) ...

随机推荐

  1. linux嵌入式系统驱动程序的阻塞与异步

    对于那些需要进程独占的设备,需要使用linux提供的阻塞编程.步骤如下: 1.在设备驱动程序中定义该设备的进程等待列多,并将其初始化 static wait_queue_head_t wait_que ...

  2. UVa 839 (递归方式读取二叉树) Not so Mobile

    题意: 递归的方式输入一个树状天平(一个天平下面挂的不一定是砝码还可能是一个子天平),判断这个天平是否能满足平衡条件,即W1 * D1 == W2 * D2. 递归的方式处理输入数据感觉很巧妙,我虽然 ...

  3. bzoj2428: [HAOI2006]均分数据

    模拟退火.挺好理解的.然后res打成了ans一直WA一直WA...!!!一定要注意嗷嗷嗷一定要注意嗷嗷嗷一定要注意嗷嗷嗷. 然后我就一直卡一直卡...发现最少1800次的时候就可以出解了.然后我就去调 ...

  4. Kafka的Producer和Consumer源码学习

    先解释下两个概念: high watermark (HW) 它表示已经被commited的最后一个message offset(所谓commited, 应该是ISR中所有replica都已写入),HW ...

  5. ucosII移植

    移植ucos II 到一个芯片上,只需要修改下面三个文件:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM. 具体来说,移植主要包括以下几项内容 (1).OS_CPU.H :用#def ...

  6. mysql大数据导出导入

    1)导出 select * from users into outfile '/tmp/users.txt';或 select * from users where sex=1 into outfil ...

  7. 【同行说技术】iOS程序员从小白到大神必读资料汇总

    在文章<iOS程序员从小白到大神必读资料汇总(一)>里面介绍了很多iOS入门学习的资料,今天小编就发几篇技术进阶的文章,快来看看吧! 一.iOS后台模式开发指南 这个教程会教你在什么时候怎 ...

  8. 【转】Qt数据库总结

    转自:http://blog.chinaunix.net/uid-25201977-id-3014100.html #include <QtSql>QT += sql QSqlDataba ...

  9. ADG打补丁

    1 产品DG备库安装 16494615 补丁 主库停止向备库传输日志 alter system set log_archive_dest_state_2=defer; alter system set ...

  10. ORACLE执行计划 explain说明

    ORACLE SQL优化工具系列之--EXPLAIN PLAN 对于oracle数据库来说,sql语句的优化可能是对性能提升最为明显的,当然对于DBA来说,也是挑战性比较大的.为了优化一个复杂的SQL ...