ADO主明细表结构处理问题二则,300分(300分)

  • 主题发起人 主题发起人 oceanwave
  • 开始时间 开始时间
我来试试;
Win2000server + D6 + officeXP + ADO
 
TO Tense:
谢谢老大呀,代码都在上面了,请老大Copy下来吧,偶的D5上运行很正常,oceanwave老兄的D6上不正常
 
做了一个DEMO,主表采用即时更新,从表采用缓存更新,代码如下:
单元代码:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, ADODB, Grids, DBGrids, StdCtrls;

type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
DataSource1: TDataSource;
DataSource2: TDataSource;
ADOConnection1: TADOConnection;
ADOTable1: TADOTable;
ADOTable2: TADOTable;
Button1: TButton;
procedure ADOTable1BeforePost(DataSet: TDataSet);
procedure ADOTable1AfterPost(DataSet: TDataSet);
procedure ADOTable1PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
procedure ADOTable2PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ADOTable1BeforePost(DataSet: TDataSet);
begin
ADOConnection1.BeginTrans;
end;

procedure TForm1.ADOTable1AfterPost(DataSet: TDataSet);
begin
ADOTable2.UpdateBatch;
ADOConnection1.CommitTrans;
end;

procedure TForm1.ADOTable1PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
begin
if ADOConnection1.InTransaction then
ADOConnection1.RollbackTrans;
end;

procedure TForm1.ADOTable2PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
begin
if ADOConnection1.InTransaction then
ADOConnection1.RollbackTrans;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Not ADOTable1.Modified and Not ADOTable2.Modified then
Exit;
if ADOTable2.Modified then
ADOTable1.Edit;
ADOTable1.Post;
end;

end.

窗体代码:
object Form1: TForm1
Left = 192
Top = 107
Width = 544
Height = 375
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object DBGrid1: TDBGrid
Left = 89
Top = 24
Width = 320
Height = 120
DataSource = DataSource1
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
end
object DBGrid2: TDBGrid
Left = 89
Top = 184
Width = 320
Height = 120
DataSource = DataSource2
TabOrder = 1
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'MS Sans Serif'
TitleFont.Style = []
end
object Button1: TButton
Left = 430
Top = 82
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 2
OnClick = Button1Click
end
object DataSource1: TDataSource
DataSet = ADOTable1
Left = 418
Top = 25
end
object DataSource2: TDataSource
DataSet = ADOTable2
Left = 417
Top = 186
end
object ADOConnection1: TADOConnection
Connected = True
ConnectionString =
'Provider=Microsoft.Jet.OLEDB.4.0;Password="";User ID=Admin;Data ' +
'Source=D:/MyLab/TEST/db1.mdb;Mode=Share Deny None;Extended Prope' +
'rties="";Jet OLEDB:System database="";Jet OLEDB:Registry Path=""' +
';Jet OLEDB:Database Password="";Jet OLEDB:Engine Type=4;Jet OLED' +
'B:Database Locking Mode=0;Jet OLEDB:Global Partial Bulk Ops=2;Je' +
't OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Passwo' +
'rd="";Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt D' +
'atabase=False;Jet OLEDB:Don'#39't Copy Locale on Compact=False;Jet O' +
'LEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False'
LoginPrompt = False
Mode = cmShareDenyNone
Provider = 'Microsoft.Jet.OLEDB.4.0'
Left = 7
Top = 6
end
object ADOTable1: TADOTable
Active = True
CacheSize = 1000
Connection = ADOConnection1
CursorType = ctStatic
BeforePost = ADOTable1BeforePost
AfterPost = ADOTable1AfterPost
OnPostError = ADOTable1PostError
TableName = 'A'
Left = 463
Top = 26
end
object ADOTable2: TADOTable
Active = True
CacheSize = 1000
Connection = ADOConnection1
CursorType = ctStatic
LockType = ltBatchOptimistic
OnPostError = ADOTable2PostError
IndexFieldNames = 'A1'
MasterFields = 'A1'
MasterSource = DataSource1
TableName = 'B'
Left = 460
Top = 187
end
end

数据结构:
表A:字段A1 Char(10),字段A2 Char(10),字段A3 Char(10)
表B:字段B1 Char(10),字段A1 Char(10),字段B2 Char(10)
 
按YNTW的代码,试了以下,没有发现问题,很正常(在d6下重新编译);
 
to Tense:
请问你试的时候不会出现以下的现象吗?
当主表在新增状态时,从表所在的DBGRID自然清空,但新增第二个从表记录时,先前
增加的从表记录不见了,也就是DBGRID始终只显示一个从表记录。当主表提交后,对应
这个主表记录的所有从表记录才显示出来。
你试试,多插入几个从表记录就会发现了。
 
>>当主表在新增状态时,从表所在的DBGRID自然清空,
当然这样,因为从表没有对应记录,应该为空;
>>但新增第二个从表记录时,先前增加的从表记录不见了,
>>也就是DBGRID始终只显示一个从表记录。
应该为这种情况,DBGrid2只显示与当前记录对应的从表记录。
>>当主表提交后,对应这个主表记录的所有从表记录才显示出来。
主表提交后,只显示[red]当前[/red]记录对应的所有从表记录;

不知你的问题是那里,或者我还没有理解(刚才又把这么多全部重看一次);
 
看来你没理由我的意思,比如我想新增以下记录
主表:
MID
00001
从表:
MID DID
00001 1
00001 2
00001 3
因为建立了主/从表关系,所以从表的MID是自动生成的
当主表在新增状态,我填入MID为0001
在主表未提交的状态下,我进入从表所在的DBGRID,在DID中填入1,MID自动显示为0001
在DBGRID我再新增一个从表记录(这里主表仍未提交),可刚才我输入DID为1的那一行不
见了。于是我在DID中填入2,MID自动显示为0001。我再新增一个从表记录同上,也只是
显示在新增状态的从表记录,我在DID中填入3,MID自动显示为0001。
这时我提交主表,刚才对应MID 0001的三个从表记录显示出来了。
这是不对的。请TENSE兄指教!
 
在不了你就不要用MASTER DETAIL关系,自己写代码,我怕它不成,
你的主表滚到,从表重新CLOSE Open 看它出来不?
 
To:oceanwave,YNTW:
我按DEMO的代码做了,出现了oveanwave说的情况,在主表不提交的情况下,新增从表的记录始终只显示一条,
提交后都显示。
环境:winNT+Delphi6+SqlServer2k
顺便问一句:对于删除,你是怎处理的?
 
>>这时我提交主表,刚才对应MID 0001的三个从表记录显示出来了。
大概你的设计有点小问题。
否则1、你的主表不保存,从表保存;(如何是好?)
2、主表没有保存,而从表该记录已输入很多,这时如果操作错误的话,
别人的辛苦就全白搭了;
建议:
主表的一条新记录提交后,才能新增该记录的从表;
 
不好意思,请问TENSE,你有没看过我上面的话,我明白在从表新增前提交主表,以解决这
个问题,但这个方法绝对不是最好的办法。我从BDE转向ADO,是因为使用ADO我可以更方
便的发布我的程序。在BDE上,我已经有很成熟、稳定的缓存更新的方案,而且当主表在
新增状态的时候,从表不会出现象我上面所提的问题。我的疑问是ADO为什么出现这种问
题,也如YNTW兄所试的,在D5中不出现这个问题,而在D6中出这个问题是为什么?
程序可以很多变通的方法,但我们要找的是一个问题出现的原因,以及最有效率、最合理
的解决方案。
 
思考中、、、
 
为什么我不想在从表新增前提交主表呢?
一、相关的从表记录与主表记录是密切相关的,如果从表的数据输入失败,那么主表相应
记录的存在也将是个错误。
二、因为主表提交后,一个事务完成。如果在从表新增前提交主表,对于一次主/从表输入
事务要用至少两次。
三、其实我真的很想够明白,这个问题究竟是什么原因?因为如果DBGRID只显示一个记录
,要么是DBGRID有问题;要么DATASET在主表新增状态时,从表也筛选出一个记录。
我有点儿明白了——当新表在新增状态时,从表新增一个记录提交后,数据库中并无此主
表记录,于是由于DBGRID不显示已提交的从表记录。当主表提交后,主表有了对应的记录。
这就象是。再深入说,就是主表在新增状态时是不是建了一个临时表(在SQL SERVER中有
一个INSERTED临时表),而当前记录的主/从关系在临时表中建立,当从表提交后,该从
表记录就不在临时表中存在,所以DBGRID不显示它。那,如果是这个原因的话,最好的办
法应该是用代码来维护这个数据库的关系。自己建这个临时表来维护主/从关系?
这个临时表中该从表
 
我想,通过这个讨论,能比较彻底的得出ADO+M/D+CacheUpdate模式的最佳应用,不但我
得益,大家都能对这个模式有更清晰的看法。
所以,真得很希望高手、大侠们不吝赐教。
为了让这个话题得以继续,讲到点上的朋友,我会另开题目给分。
再次谢过!
 
非常同意oceanwave的:
我在DBE上已经用过无数次啦(夸张)oceanwave说的这种方法,因为在进销存的帐单上,经常要
用到这种方式,但最近我转到ADO,发现了这个问题,正没有办法解决呢!我肯定这是
borland在BDE上特地做了文章,而ADO就没有啦,所以正愁没办法解决?
采用先POST主表的记录是个很笨的方法,难道用户在编辑时取消,都要删除刚POST的
主记录,因为其实这时候用户还没真正做保存操作!
还有,ADO不但在cachedupdate模式是这样,其它所有模式都这样,这就是说,不要想
在ADO中使用主从结构的这种从记录先保存后在保存主记录?
 
为什么没人回答我?
 
关注!!!
刚升到ADO 同样得问题 如果没有好的解决方法,之后回到BDE了,
BDE里用两个UPDATESQL帮定在M/D上一起在事务里,已经用的很好了
另:ADO CacheUpdate模式单表ADD多条记录后,CANCEL报错,EDIT不会????
 
照这样看,基本上可以认为是D6对ADO的支持有问题,因为我在我的环境下运行上面的代码很正常,
再说明一下我的环境,各位老兄都比较一下:D5+ADO 2.5(中文)+ACCESS97,未打过补丁

BTW:不是我不想打补丁,而是一打补丁,D5就垮了:(
 
[red]关注:困扰我很久的问题。如果在这里能解决就太好了。[/red]

To:YNTW
oceanwave说的从表不显示在问题,我在d5下也曾经遇到过,恐怕不是d5 与 d6 版本的关系
之么简单。

由于这个问题的困扰,我现在只能放弃了缓存更新。或使用先存主表再存从表这个ben办法! [:(]
 
后退
顶部