十万火急,求三层数据保存问题。(100)

  • 主题发起人 主题发起人 zpselect
  • 开始时间 开始时间
Z

zpselect

Unregistered / Unconfirmed
GUEST, unregistred user!
是这样的,我们现在的架框用的是三层架构。中间层主从孙表,是通过ID来关联的,但是前台提交明细数据时会报:cannot perform this operation on a closed dataset,这是中间层报出来的,但是,从头到尾都没有关闭过从表的数据集,不知道为什么服务器端的从表数据集会自动关闭掉?如果服务器端的TDataSetPrivoder的beforeApplyUpdates事件里判断一下就可以了,即:if not qryDetail.active then
begin
qryDetail.close;
qryDetail.open;
end但是这样做的话,也会带来的一些问题,因为中间层重新从后台查了一次,那么可能导致前台记录批针与中间层记录的指针位置不一致,那么会报:当前记录没有找到或者被其它者所用。
 
[h1][/h1][red][/red]
 
中间层设计关联数据结构问题.
 
我也是这么想的,我有测试过,如果单表的话,不会报错,就是请从表类型的模块都会报错。由天这个数据关联数据结构是另外一个同事写的(他已辞职)请,007vivi给出正确的关联方式
 
这个问题我以前开发系统也出现过,这是你采用三层架构在线设计,所出现的问题。你试一试将每次更新的数据用SQL执行就没有问题了。
 
更新数据不能用SQL来执行的。因为明细太多,而且有孙表,甚至更下一层的子表。不可能用SQL语句的,谁有三层架框的成功案例,望肯提供一份学习的资料,在此为谢。
 
[:D]在下在实现了QuickBurro分布式多层架构后,在该架构之上实现了远程数据库的对象化(即远程数据库实体类),编写了一个实用的实体类代码生成工具GetEntity.exe,经实际项目中的应用证实,较为实用。该工具支持“简单实体类、批量实体类、动态实体类、主从实体类”四种代码生成方式,能对任意远程节点上的数据库进行对象化转换,生成可在Delphi下直接编译通过的类单元。生成的主从表实体类能和QuickBurro的应用层数据库事务处理功能结合起来使用,解决多表远程更新处理问题。下面是使用该工具自动生成的一个主从表实体类单元代码的声明部分://// ------------------------------------------------------------------------------------//// Entity_Sale.pas -- This entity class unit for table "Sale". //// Generated by QuickBurro V3.2.2.0 Entity Classes Generator//// Generate time: 2010-06-01 15:47:01//// Copyright (C) Jopher Software Studio, 2006-2010//// ------------------------------------------------------------------------------------//unit Entity_Sale;interfaceuses SysUtils, Classes, db, DBClient, SyncBurro, QBParcel, Entity_SaleDetail;type TSale = class(TPersistent) Private ff_SaleId: String;
ff_SaleDate: String;
ff_CustId: String;
ff_CustName: String;
ff_LevelId: String;
ff_LevelName: String;
ff_OrderDate: String;
ff_OrderName: String;
ff_TransMode: String;
ff_TransId: String;
ff_TransName: String;
ff_TransTelephone: String;
ff_TransEvidenceId: String;
ff_TransMoney:do
uble;
ff_ReceiveAddress: String;
ff_ReceiveZip: String;
ff_ReceiverName: String;
ff_ReceiverTelephone: String;
ff_ReceiverFax: String;
ff_SaleMoney:do
uble;
ff_MoneyId: String;
ff_MoneyName: String;
ff_EvidenceId: String;
ff_CreateDate: String;
ff_CreaterUserId: String;
ff_CreaterUserName: String;
ff_OutOk: String;
ff_SaleDetail_List: TSaleDetailList;
class function CreateCds: TClientDataset;
public Property f_SaleId: String read ff_SaleId write ff_SaleId;
Property f_SaleDate: String read ff_SaleDate write ff_SaleDate;
Property f_CustId: String read ff_CustId write ff_CustId;
Property f_CustName: String read ff_CustName write ff_CustName;
Property f_LevelId: String read ff_LevelId write ff_LevelId;
Property f_LevelName: String read ff_LevelName write ff_LevelName;
Property f_OrderDate: String read ff_OrderDate write ff_OrderDate;
Property f_OrderName: String read ff_OrderName write ff_OrderName;
Property f_TransMode: String read ff_TransMode write ff_TransMode;
Property f_TransId: String read ff_TransId write ff_TransId;
Property f_TransName: String read ff_TransName write ff_TransName;
Property f_TransTelephone: String read ff_TransTelephone write ff_TransTelephone;
Property f_TransEvidenceId: String read ff_TransEvidenceId write ff_TransEvidenceId;
Property f_TransMoney:do
uble read ff_TransMoney write ff_TransMoney;
Property f_ReceiveAddress: String read ff_ReceiveAddress write ff_ReceiveAddress;
Property f_ReceiveZip: String read ff_ReceiveZip write ff_ReceiveZip;
Property f_ReceiverName: String read ff_ReceiverName write ff_ReceiverName;
Property f_ReceiverTelephone: String read ff_ReceiverTelephone write ff_ReceiverTelephone;
Property f_ReceiverFax: String read ff_ReceiverFax write ff_ReceiverFax;
Property f_SaleMoney:do
uble read ff_SaleMoney write ff_SaleMoney;
Property f_MoneyId: String read ff_MoneyId write ff_MoneyId;
Property f_MoneyName: String read ff_MoneyName write ff_MoneyName;
Property f_EvidenceId: String read ff_EvidenceId write ff_EvidenceId;
Property f_CreateDate: String read ff_CreateDate write ff_CreateDate;
Property f_CreaterUserId: String read ff_CreaterUserId write ff_CreaterUserId;
Property f_CreaterUserName: String read ff_CreaterUserName write ff_CreaterUserName;
Property f_OutOk: String read ff_OutOk write ff_OutOk;
Property f_SaleDetail_List: TSaleDetailList read ff_SaleDetail_List write ff_SaleDetail_List;
constructor Create;
destructor Destroy;
override;
class function ReadFromCds(aCds: TClientDataset): TSale;
procedure LoadAppertains(NodeId: String;
SBurro: TSyncBurro);
function SaveToCds(Cds: TClientDataset): Boolean;
class function ReadFromDB(NodeId: String;
SBurro: TSyncBurro;
Condition: String): TSale;
function DeleteFromDB(NodeId: String;
SBurro: TSyncBurro;
Condition: string): boolean;
function InsertToDB(NodeId: String;
SBurro: TSyncBurro;
var NewKeyValue: integer): boolean;
function UpdateToDB(NodeId: String;
SBurro: TSyncBurro;
Condition: string): boolean;
end;
TSaleList = class(TList) public constructor Create;
destructor Destroy;
override;
class function ReadFromDB(NodeId: String;
SBurro: TSyncBurro;
Condition: string = '';
OrderBy: string = ''): TSaleList;
class function ReadFromCDS(Cds: TClientDataset): TSaleList;
function SaveToCds(aCds: TClientDataset): boolean;
function SaveToFile(FileName: string;
DataFormat: TDataPacketFormat): boolean;
function LoadFromFile(FileName: string): boolean;
function SaveToStream(aStream: TMemoryStream;
DataFormat: TDataPacketFormat): boolean;
function LoadFromStream(aStream: TMemoryStream): boolean;
function SaveToParcel(aParcel: TQBParcel;
GoodsName: string): boolean;
function LoadFromParcel(aParcel: TQBParcel;
GoodsName: string): boolean;
end;
implementation...GetEntity.exe工具所生成的实体类代码基于QuickBurro的数据集读服务、记录新增服务、记录更新服务、运行SQL命令等几个基本的服务,而这些服务都在QuickBurro的数据库事务控制服务内,所以,您在使用实体类的方法时,可以在自己的程序里使用QuickBurro的数据库事务,使之包含实体类读写的方法,这对于提高系统的可靠性有重要意义。本工具的最新版本支持单个实体类、批量实体类、动态实体类、主从关系实体类等四种代码生成方式,使应用程序对远程的普通二维表、主从关系多数据表等多种数据的远程交互编程时,都能获得最大的编程效率。下面是基于主从实体类的主从表记录增删改编程方法示例://// 新增:单据保存到数据库,因主从类实体,最好用事务处理方式进行...... SyncBurro1.begin
Trans(form1.QBConnection1.NodeId);
if Order.InsertToDB(QBConnection1.NodeId,SyncBurro1,j) then
begin
if not SyncBurro1.CommitTrans(j) then
begin
SyncBurro1.RollbackTrans;
application.MessageBox('对不起,写入数据库失败,请检查数据的有效性!','操作提示',mb_ok+mb_iconinformation);
exit;
end;
end;
......//// 修改:单据更新到数据库,因主从类实体,最好用事务处理方式进行...... SyncBurro1.begin
Trans(QBConnection1.NodeId);
if order.UpdateToDB(QBConnection1.NodeId,SyncBurro1,'orderid='+inttostr(order.f_OrderId));
begin
if not SyncBurro1.CommitTrans(j) then
begin
SyncBurro1.RollbackTrans;
application.MessageBox('对不起,更新数据库失败,请检查数据的有效性!','操作提示',mb_ok+mb_iconinformation);
exit;
end;
end;
......//// 删除:开始执行删除,因主从类实体,最好用事务处理方式更新数据库... SyncBurro1.begin
Trans(QBConnection1.NodeId);
if Order.DeleteFromDB(QBConnection1.NodeId,SyncBurro1,'OrderId='+inttostr(Order.f_OrderId)) then
begin
if not SyncBurro1.CommitTrans(j) then
begin
SyncBurro1.RollbackTrans;
application.MessageBox('对不起,删除销售单据出现错误!','错误信息',mb_ok+mb_iconerror);
exit;
end;
end;
以上三个代码段均为多表操作,使用了QuickBurro开发包所支持的事务处理,可靠性高但写法非常简单
 
谢谢各位朋友的帮助,小弟有一事不明,中间层的主从孙表的关系通过ID来关联,(中间层没有做关闭ADO的任何语句),客户端ApplyUpdate(0),之后,就报cannot perform this operation on a closed dataset,但是单表的话,不会报任何的问题,我认为是主从表的关联方式出了问题,请问怎样解决这种情况?
 
1、三层的中间层做主从表在大数量量的情况下效率很差,主从孙就更差了,建议不要这样设计2、提交主表的修改后会自动提交从表,一般情况下不用再提交从表。
 
谢谢各位的顶力发言,我现在想将客户端的主从孙(甚至更下一层,每个模块的表的层数不确定,有主从,有单表,也有主从孙,主从孙孙...)的数据集通过中间层的接口方法,传到中间层去提交数据,请问哪位有中间层这方面的代码不?望其享一下,谢谢。(我自已试了一些方法,但未成功)
 
如果不喜欢用QuickBurro的复合实体类实现,则也可以使用QuickBurro的“Delta提交+远程事务”方式来实现,这种方式允许你连续提交多份Delta数据(即TQBClientDataset的编辑结果数据)且保证远程数据写入的安全性。举例如下:假定主、从、孙三个QBCds中已经包含了编辑的结果,则可以这样写程序:SyncBurro1.begin
Trans(NodeId);QBCds1.CommitToRemote(NodeId,Table1,KeyFieldList1);QBCds2.CommitToRemote(NodeId,Table2,KeyFieldList2);QBCds3.CommitToRemote(NodeId,Table3,KeyFieldList3);
if not SyncBurro1.CommitTrans(RetId) then
SyncBurro1.RollbackTrans;-----------------------------------------------这样的提交形式,是不是很简单?
 
只用主表提交简单..爽..不要写那么多~~
 
对于三层,主从表关联的提交2、提交主表的修改后会自动提交从表,不用再提交从表。 在ClientDataSet的主表中,是以蜂巢表的形式保存的,提交主表就行
 
楼主,你要在服务端的主从表的主表onscroll事件中写上这句话话就不会出错了:With AdoDetaildo
begin
close;
Params.Parambyname('参数').value := DataSet.Fieldbyname('ID').asstring;
open;
end;
另从表的语句是:sql.text:='select * from detail where sbillno=:ID'如果从表还有从表,就依次类推,这样就会把相关的从表打开了,不再会出错,我这边一直都是这样,很正常的。
 
TO Supermay:我们现在就是采用蜂巢表的方式提交,一提交就报:cannot perform this operation on a closed dataset,你可否共勉一下你的提交代码?TO yagzh2000:我们现在就是用的是close,open方式,来同步前台和TDataSetPrivdor之间的数据,但点搜索之后,再去新增数据-->保存-->编辑,然后保存就会报:record not found or changed by another user ,你可否也共勉下你的接交方式和表与表之间的关联方式?在此感谢。我的邮箱是:zpselect@126.com
 
可以参考一下:http://delphibbs.com/delphibbs/dispq.asp?lid=3816911
 
这种问题可能是你某个地方对close数据进行操作而产生,可能通过对中间层调试来找到具体地方
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
875
DelphiTeacher的专栏
D
后退
顶部