关于多层数据库的操作方法问题?(300分)

  • 主题发起人 主题发起人 free_knight
  • 开始时间 开始时间
F

free_knight

Unregistered / Unconfirmed
GUEST, unregistred user!
最近接触了多层数据库,要开发一个CRM或是ERP,用的是MIDAD+DCOM,发现了一个比较困惑的问题:
在客户端对数据库里的表进行添加,删除,修改操作,不知道用什么方法好,我用了以下几个方法,
都觉的不好:
1:在客户端的 ClientDataSet.CommandText 中直接写SQL语句进行操作,
如:ClientDateSet.CommandText:='insert table1(f1,f2) values(:v1,:v2)';
2:在服务端写方法,然后在客户端调用,把SQL语句的参数也一并传过去。
如:DCOMConnection1.AppServer.InsertTable1(vf1,vf2);
3:在客户端直接操作,再用 ClientDataSet1.ApplyUpdates(0);
让Delphi自动完成对数据库的操作。
可是都觉的不好,希望大家给我些好的方法。
各位有这方面的经验么,可否指点一二,不甚感激。
还望各位多多发表自己的见解,不吝赐教。
 
1、直接在ClientDataSet中增加,用ClientDataSet1.ApplyUpdates(0)会自动增加到数据库中
2、利用服务器提供的函数增加InsertTable(insertsqlstring)
根据你的数据库和数据量选择合适的方式
 
多层的精华就是用ClientDataSet + ApplyUpdates
服务器端TDataSetProvider设定为ResolveToDataSet=False(默认)时会自动生成SQL语句
insert/update/delete等对数据库进行操作,客户端可以对SQL的生成有一定的控制,有点
象用TUpdateSQL实现CachedUpdate.
 
ApplyUpdates以前在client的内存中,ApplyUpdates以后就提交到server
 
各位,除了我上面提到的几种方法外,还有没有其他的方法?
这几种方法有什么特点?
 
要根据情况来用的,一般要用dbgrid显示的用applyupdata,象更新表的一批数据或者删除数
据就用DCOMConnection1.AppServer.InsertTable1(vf1,vf2);
 
各位大侠,能不能把你们实际的经验,还有使用的例子简单的给我们这些菜鸟介绍一下,
(不需要涉及你们的核心技术),只要简单的介绍些实际应用的例子就好,我想很多人
都想知道。
 
你的问题主要是应用层如何处理的问题,客户段只是界面,真正调用的是ado组件,也就是说
如何在应用层封装业务处理是关键!
 
也就这几种方法吧!
你就用的 ClientDataSet.CommandText 就可以!
只要把问题解决就可以!
我个人认为远程调用如 --DCOMConnection1.AppServer.InsertTable1(vf1,vf2);
能不用还是不用,还要保护,挺麻烦的! :)
 
自己定义方法,然后客户端执行更接近三层的定义,所以在应用层封装业务处理是关键!
 
还有远程调用可以试一试!
 
各位大侠,有没有实际使用的例子简单的给我们这些菜鸟介绍一下,
(不需要涉及你们的核心技术),只要简单的介绍些实际应用的例子就好!
如果有条件的话,就提出来,尽量满足
 
free_knight:你对同一问题开了两个贴。我在另一贴中简要回答如下:
>1:在客户端的 ClientDataSet.CommandText 中直接写SQL语句进行操作,
> 如:ClientDateSet.CommandText:='insert table1(f1,f2) values(:v1,:v2)';
:不好,破坏了应用程序服务器端企业对象的封装。
>2:在服务端写方法,然后在客户端调用,把SQL语句的参数也一并传过去。
如:DCOMConnection1.AppServer.InsertTable1(vf1,vf2);
:有点沾边了,但仍然没有实现严格的封装。
>3:在客户端直接操作,再用 ClientDataSet1.ApplyUpdates(0);
让Delphi自动完成
对数据库的操作。
:这个方法作为对少量数据操作的折衷可以保留,如:对字典的维护就可以这样简单地实现。
建议:
使用三层就意味着面向对象,也就意味着客户端不能直接提交“原始格式的记录”,
而是“业务数据包”,应用程序服务器端的企业对象接收到该数据包后,再进行验证,处理。
刚开始这样做时,可能觉得不胜麻烦,但做成之后,却是一个维护方便完全面向对象的
应用。如果条件允许,应当尽可能这么做。
既然回复了这么多,不妨贴一个例子,请注意例子中用*******标注的说明:
{应用服务器类 凡公共方法一律加异常保护}
TfrmGaugeCorbaDM = class(TCorbaDataModule, IfrmGaugeCorbaDM)
AccountBooks: TAccountBooks;
Gauges: TGauges;
Vouchers: TVouchers;
***************************************
上述全部是企业对象的指针,当然这个例子还不够好,缺少事务控制对象。
***************************************
ExtDataBase: TExtDataBase;
***************************************
上面是兼作事务控制的数据库连接对象
***************************************
{通过保密远程数据集定义帐薄组的安全认证方法}
procedure AccountBooksGroupUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{通过保密远程数据集定义帐薄的安全认证方法}
procedure AccountBooksUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{通过保密远程数据集定义制造商的安全认证方法}
procedure GaugesManufacturerUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{通过保密远程数据集定义铭牌的安全认证方法}
procedure GaugesNameplateUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{通过保密远程数据集定义规格的安全认证方法}
procedure GaugesSpecsUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{通过保密远程数据集定义凭证的安全认证方法}
procedure VouchersDefineUpdateData(Sender: TObject;
DataSet: TClientDataSet);
***************************************
注意上述是对IProvider提供的字典表接口的验证方法,即使允许客户端直接提交修改
也是要加验证的。
***************************************
private
FClientApplication, {客户应用名}
FClientMachine, {客户机器名}
FLoginName, {用户注册名}
FLoseCode : string;
{检查档案程序查出的脱帐设备条码清单}
FDBC : TDBConnect;{数据库连接器的对象指针}
{取字典的方法指针}
FGetDictMethod: array[Low(TDictKind)..High(TDictKind)] of TGetDataMethod;
FIrregularly : TIrregularly;{不规则接口,用作与非三层协调 ******* 临时措施}
FLastTime : TDateTime;
{最后一次收到客户连接信号的时间}
{方法分类指针组}
FMethodGroup : array[Low(TMethodType)..High(TMethodType)] of TList;
FObjectsPtr : array[Low(TMethodType)..High(TMethodType)] of TRWTableDBTOpr;
FSerial : Integer;
{客户连接序号}
FSignalChange : Boolean;
{信号变化标志}
FTacheController: array of TVoucherEmbedded;{环节控制器表}
{生成凭证对应的凭证编号}
FVoucherID : array[pkUsed..pkDiscard, False..True] of Integer;
{检查基础档案的回调函数.返回False时中止检查档案}
function CheckArchive(Buff: Pointer): Boolean;
{将帐薄组代码表转换为帐薄组子帐名称表}
function GetAccountGroupNameList(Codes: PWord): string;
{取所有帐薄的不完全定义(客户端不需要冗长的帐薄完全定义)}
function GetAllAccountList: OleVariant;
function GetAllUser: OleVariant;{取所有用户的不完全注册(无用户号及密码)}
function GetAllWindowClass: OleVariant;{取所有的窗口类注册}
{取电能表检测工单的符合系统参数要求的最终结论}
function GetMeterCheckBillVerdict(Bill: PMeterCheckBillRec): Boolean;
{取环节控制对象. 若没有找到现成的环节控制对象就,尝试动态建立它}
function GetTacheController(VoucherNo: SmallInt;
out Err: Word): TVoucherEmbedded;
function GetWorkBillDeptNo: TIntList;{取得工事票允许的部门编号表}
{公用安全认证者,是数据安全的最后防线,对于非法操作,只是忽略,并不返回信息}
procedure SecurityAttester(HeadInfo: PSecrecyPacketHeadInfo;
DataSet: TClientDataSet;
const Msg: string);
{通过保密远程数据集定义产品分类名的安全认证方法}
procedure TradeNameUpdateData(Sender: TObject;
DataSet: TClientDataSet);
{事务中止处理,防止事务扩大}
procedure TransactionCommeIn(const Method: string;
Normal: Boolean);
protected{创建计量器具档案.GroupNo是建档对应帐册组号,UserHandle是用户句柄,
ClassNo是操作发出对象的类号,Machine是操作发出机器名,Data是档案记录,Kind是建档类型}
function AddGaugeRec(GroupNo: Smallint;
UserHandle, ClassNo: Integer;
const Machine: WideString;
Data: OleVariant;
Kind: Byte): Word;
safecall;
{增加一组电能表检测工单.这一组检测工单必须属于同一电能表.若原有检测工单则替
代,但保留维修人}
function AddMeterCheckDetails(MCDS: OleVariant): Word;
safecall;
{提交凭证}
function ApplyVoucher(Data: OleVariant;
out ApplyTime: TDateTime;
out Ord: Word): Word;
safecall;
{检验客户填写的工事票}
function BackfillCheck(New: WordBool;
const SetupBarCode,
RemoveBarCode: WideString): Word;
safecall;
{取消指定的未过帐凭证,并解锁计量器具档案}
function CancelVoucher(Time: TDateTime;
Ord: Word): Word;
safecall;
{维护数码签名}
function ChangeIdiograph(Opr: Byte;
DeptNo: Smallint;
const SurName, Name,
OldIdiograph, NewIdiograph: WideString): Word;
safecall;
{改变指定员工在指定模块上的签名身份}
function ChangeIdiographPosition(ClassNo, EmployeeNo: Integer;
const Position: WideString): Word;
safecall;
{修改登录密码}
function ChangePassword(UserHandle: Integer;
const PSW,
NewPSW: WideString): Word;
safecall;
{核对指定的帐薄与存量表是否匹配,若出错,指出错误科目}
function CheckAccountAndStock(AccNo: Word;
out Err: Word): WideString;
safecall;
{把存量表与基础档案的科目,帐册指示核对.若存在错误,返回错误信息包}
function CheckCodeStock(AccNo: Smallint): OleVariant;
safecall;
{设置走字测试示数,结论及封印号}
function CheckCounter(const BarCode, Speller, Seal: WideString;
Counter: OleVariant;
OK: WordBool): Word;
safecall;
{检查指定用户是否拥有对指定模块的指定权限}
function CheckPrivilege(UserNo: Integer;
Privilege: Byte;
ClassNo: Integer): WordBool;
safecall;
{接收客户机的连通信号。若超过指定周期没有收到该信号,计时器程序就会自动释放
该客户的应用服务器模块。这些处理是封闭的(不与实体描述类实例发生关系),
因而是线程安全的。}
procedure ConnectSignal(const UserName, Machine,
AppName: WideString);
safecall;
{修正账目附加存量表.专用于数据维护}
function CorrectAccount(AccNo: Smallint;
Time: TDateTime;
Ord: Word;
StorageAmount: OleVariant): Word;
safecall;
{根据档案重新生成指定科目指定帐册的有码存量记录}
function CorrectCodeStock(AccNo: Smallint;
const Subject: WideString): Word;
safecall;
{判断是否存在指定科目或其子科目的存量(意味着有载帐数量)}
function ExistsStock(const Subject: WideString): WordBool;
safecall;
{查找指定帐薄组允许的商品类型}
function GetAccountBookGroupTradeType(No: Word): WideString;
safecall;
{取指定凭证的已方或对方允许的帐薄清单}
function GetAccountListOfVoucher(VoucherNo: Word;
SelfSide: WordBool;
out Err: Word): OleVariant;
safecall;
{取指定科目表在指定帐册组中对应的帐册号表}
function GetAccountsNo(GrpNo: Smallint;
const Subjects: WideString): OleVariant;
safecall;
{取指定部门的职工花名册}
function GetDeptEmployeeNameList(DeptNo: Word): OleVariant;
safecall;
function GetDict(Dict: Word): OleVariant;
safecall;{取指定的字典}
{取指定模块的版本}
function GetEdition(const ClassName: WideString): WideString;
safecall;
{取记帐实际可能的管理模式(对已方、对方管理模式的交集)、记帐科目}
function GetFactAllowableSubject(Grp1, Grp2: Integer;
out Mode: Byte): WideString;
safecall;
{取指定通用计量器具的详细档案}
function GetGaugeDetail(const BarCode: WideString;
out Err: Word): OleVariant;
safecall;
{取指定条码的计量器具档案}
function GetGaugeRec(const BarCode: WideString;
out Err: Word): OleVariant;
safecall;
{取电能表检测工单组}
function GetMeterCheckDetails(const BarCode: WideString;
Times: Byte;
out Err: Word): OleVariant;
safecall;
{取某人在指定模块上的签名身份}
function GetIdiographPosition(ClassNo, EmployeeNo: Integer): WideString;
safecall;
{取指定日期范围的检定员工作量数据.InCheck指示是取在检工作量还是已退库工作量,
Detail指示是否取被检条码清单}
function GetLoad(BYear: Word;
BMonth, BDay: Byte;
EYear: Word;
EMonth,
EDay: Byte;
InCheck, Detail: WordBool;
out Err: Word): OleVariant;
safecall;
{取模块名}
function GetModuleName(ModuleNo: Integer): WideString;
safecall;
{取指定编码的铭牌注册}
function GetNamePlate(const TradeType: WideString;
out Err: Word): OleVariant;
safecall;
{取指定用户在指定模块上的权限}
function GetPrivilege(UserNo, ClassNo: Integer): Byte;
safecall;
{取得指定角色在指定类上的授权}
function GetRolePrivilege(RoleNo, ClassNo: Integer): Byte;
safecall;
{取服务器名}
function GetServerName: WideString;
safecall;
{按帐薄组号,管理模式集,分类编码取存量}
function GetStock(GroupNo: Integer;
Manage: Byte;
const TradeType: WideString;
out Stock: Integer):do
uble;
safecall;
{按帐薄组名,管理模式集,分类编码取存量}
function GetStockEx(const Group: WideString;
Manage: Byte;
const TradeType: WideString;
out Stock: Integer):do
uble;
safecall;
{取指定帐薄,指定管理模式的全部存量记录}
function GetStocks(AccNo: Word;
Manage: Byte): OleVariant;
safecall;
{取系统参数集}
function GetPublicParams: OleVariant;
safecall;
{取指定角色被授与的模块编号表}
function GetUsableClassList(RoleNo: Integer): OleVariant;
safecall;
{取用户菜单.将较高级的菜单放在末端}
function GetUserMenu(UserNo: Integer): OleVariant;
safecall;
{取指定用户的角色号表}
function GetUserRoleList(const UserName: WideString): OleVariant;
safecall;
{取指定的凭证定义及允许使用的已方、对方帐薄名表}
function GetVoucherDef(No: Word;
out SelfSide, OtherSide: WideString;
out Err: Word): OleVariant;
safecall;
{取指定阶段的工事票记录.Setup为False时,BC>=MinBarCodeWidth则不用TradeType与
Serial参数,否则用TradeType、Serial而不用BC参数}
function GetWorkBill(const BarCode, TradeType, Serial: WideString;
Setup: WordBool;
Phase: Byte;
out Err: Word): OleVariant;
safecall;
{取工事票允许使用的部门定义列表}
function GetWorkBillDepartments: OleVariant;
safecall;
{按是否新装,管理模式集,分类编码取(已返待填的)工事票存量}
function GetWorkBillStock(New: WordBool;
Manage: Byte;
const TradeType: WideString): Integer;
safecall;
function GetWorkBillStocks: OleVariant;
safecall;
***************************************
仅对下述字典表允许直接使用Iprovider接口提交数据
***************************************
{取帐册定义的数据接口属性}
function Get_AccountBookDefProvider: IProvider;
safecall;
{取指定编号帐薄的接口}
function Get_AccountBookProvider(AccNo: Word): IProvider;
safecall;
{取帐册组定义表接口属性}
function Get_AccountGroupProvider: IProvider;
safecall;
function Get_DepartmentProvider: IProvider;
safecall;
{取帐薄的设计时接口}
function Get_ExampleAccountBookProvider: IProvider;
safecall;
{取工事票的设计时接口}
function Get_ExampleWorkBillProvider: IProvider;
safecall;
{取自动在卷间切换的通用计量器具档案数据接口属性}
function Get_GaugesProvider: IProvider;
safecall;
{取制造商注册表的接口}
function Get_ManufacturerProvider: IProvider;
safecall;
{取普通产品分类表的接口}
function Get_MillRunName: IProvider;
safecall;
{取铭牌注册表的接口}
function Get_NamePlateProvider: IProvider;
safecall;
{取规格注册表的接口}
function Get_SpecsProvider: IProvider;
safecall;
{取商品铭牌视图数据接口属性}
function Get_TradeNamePlateProvider: IProvider;
safecall;
{取凭证定义表接口属性}
function Get_VoucherDefProvider: IProvider;
safecall;
{取未处理/已处理凭证子条目接口属性}
function Get_VoucherItemProvider(History: WordBool): IProvider;
safecall;
{取未处理/已处理凭证接口}
function Get_VoucherProvider(History: WordBool): IProvider;
safecall;
{取工事票接口}
function Get_WorkBillProvider(Phase: Byte): IProvider;
safecall;
***************************************
到此,所有的字典IProvider接口都在这儿了。
***************************************
{解释电子签名:签名,类名,身份}
function IdiographToName(const Idiograph, ClassName,
Position: WideString): WideString;
safecall;
{临时性统计查询.Exec指示是否有返回值(用作非查询语句),Exec为True时,返回值恒为0;
为False时返回查询结果集的第一行的第一个字段的值. ******* 临时措施}
function OpenQuery(const SQL: WideString;
Exec: WordBool;
out Err: Word): Integer;
safecall;
{记录维修人.若无检测工单,则生成空的检测工单}
function Repair(const CodeList, Name: WideString): Word;
safecall;
{授与指定角色类操作权限.UserHandle是用户句柄,OprClsNo是操作发出类的编号,
RoleNo是被授权角色号,ClassNo是授与类号,RoleName是新增或修改的角色名,Enabled决定
角色是否使能,Priv是授与权限,OprType是操作方式}
function RolePrivilege(UserHandle, OprClsNo, RoleNo, ClassNo: Integer;
const RoleName: WideString;
Enabled: WordBool;
Priv,
OprType: Byte): WordBool;
safecall;
{按照档案核对存量表,若发现脱帐的设备,返回其条码清单}
function ScanGauges: WideString;
safecall;
{环节测试}
function TacheTest(const BarCode: WideString;
VoucherNo: Smallint;
out Err: Word): OleVariant;
safecall;
{增加工事票催还次数或核销被索赔资产}
function TakeCountOrAmends(Amends: WordBool;
const CodeList: WideString): Word;
safecall;
{接收新装工事票,锁定并调整(已返待填的)工事票存量}
function TakeOverNewSetupWorkBill(const CodeList: WideString): Word;
safecall;
{将指定时刻发生的凭证过帐}
function TransferItems(OccurTime: TDateTime;
Ord: Word): Word;
safecall;
{将一批返填的工事票依具体情况转为计划/废弃;将被装,被撤设备通过聚合制单转帐.
这些工事票可能是属于不同部门的,这意味着要生成未知数量的凭证}
function TransferWrokBill(Data: OleVariant): Word;
safecall;
{修正设备参数}
function UpdateGaugeParams(Data: OleVariant): Word;
safecall;
{取用户注册}
function UserLogin(const User, Password: WideString): OleVariant;
safecall;
{用户授权.UserNo是管理者的用户句柄,ClassName是管理者使用的类名,Role是被授与
用户的角色,UserName是接授者的用户名,Title是客户端标题,Enabled是该用户是否可登录
标识,OprType是操作类型}
function UserPrivilege(UserHandle, ClassNo, RoleNo: Integer;
const UserName,
Title: WideString;
Enabled: WordBool;
OprType: Byte): WordBool;
safecall;
{凭证审批, Pass=True为批准}
function VoucherPass(Time: TDateTime;
Ord: Word;
Pass: WordBool;
const Ratifier: WideString): Word;
safecall;
{回填工事票}
function WorkBillBackfill(WBR: OleVariant): Word;
safecall;
{写异常日志}
procedure WriteLog(const ClassName, Memo: WideString;
UserNo,
Res: Integer);
safecall;
public
WorkBills : TWorkBills;
{工事票管理对象}
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
// procedure DisConnect;{断开数据库连接}
function GetResource(ResNo: Integer): WideString;
safecall;{取字符串资源}
{提交凭证的内部过程,被TransferItems和环节控制对象调用}
function InterTransferItems(VD: PVoucherDetail;
Unlock: Boolean): Word;
{为当前用户打开对象实例}
procedure OpenObjects(MethodPtr: Pointer;
const MethodType: TMethodTypeSet);
property ClientApplication: string read FClientApplication;{客户应用名}
property ClientMachine: string read FClientMachine;
{客户机器名}
property LoginName: string read FLoginName;
{用户注册名}
property LastTime: TDateTime read FLastTime;{最后一次收到客户连接信号的时间}
property Serial: Integer read FSerial;
{客户连接序号}
{信号变化标志}
property SignalChange: Boolean read FSignalChange write FSignalChange;
end;
***************************************
除了字典修改之外,所有业务都由客户端提交“业务数据包”,再由上面的这些众多方法
转给相应的企业对象处理。
***************************************
不知上述例子可否?
 
收到,嘿嘿~~
 
多谢诸位大侠,特别是sharejoy大大大大大大大大大大大大大大大大大大侠。
小生我有点头绪了, 以后有问题再请指教。
 
后退
顶部