痛哭的人:关于ado主从表的头痛问题...若解决,另奉100分!(200分)

H

h_q_p

Unregistered / Unconfirmed
GUEST, unregistred user!
近段将以前用BDE写的系统改ADO.主从表是用ADOQuery,在form上,主表用
TDBEdit控件作为输入控件,从表用TDBGrid作输入控件。
现问题是:
当新增时一笔主表后新增从表时:DBGrid中只能显示当前输入之明细资
料,即输入第二笔时,第一笔不见了,增第二笔时,前二笔不见了,但保
存后显示正常。

请教各位富翁:怎样才能显示全部资料?
 
建议你主表用即时更新,从表用缓存更新,另外,修改主表后先Post,再修改从表。
另外,你先搜索一下吧。这儿应该有许多类似答案的。
 
确保将主表post了以后再插入从表纪录
 
謝謝 zhangkan ,rustle!
但若要cancel哪怎麼辦?新增的主表可以刪除,但修改的
主表呢?哪怎樣才能還原至初始狀態?
 
可以试试事务处理
 
to dependmyself:
事務會導致相關表鎖定,而從post開始到最後的Save或cancel之間的
時間不可預估,這樣會導致表鎖死時間可能過長,這可是不希望看到
的,特別是在較大型系統中...
 
確保新增成功后﹐再新增。記得每一次下定要成功﹐再做另一筆
 
我这么做过,没问题呀,你用的D5吗?如果是D5是要装那个ADO升级包的。
 
開發環境:
pwin200+sp2
d6+sp2
sql server 2000
 
这个问题我也遇见过,我现在是从表Post后,关闭再打开的,然后定位到当前记录
听听其他人的:)
 
没时间整理和加上说明,大概做法如下

function TfrmIn.Enter:integer;
begin
try
sMaster.DataSet.Open;
acNew.Execute;
finally

end;
result:=showmodal;
end;

function TfrmIn.Edit(OrderNo:string):integer;
begin
try
sMaster.DataSet.Open;
sMaster.DataSet.Locate('OrderNo',OrderNo,[]);
finally

end;
result:=showmodal;
end;

procedure TfrmIn.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if DM.isEditing then
if messagebox(application.Handle,'当前单据正在编辑中,是否要保存修改?','警告',MB_YESNO+MB_DefButton1+MB_IconStop+MB_ApplModal)=IDYes then
acSave.Execute;
// canclose:=dm.DataSetApplyUpdates(dm.tPIncMaster,ModalResult=mrOK);
end;

procedure TfrmIn.PickIt;
begin
frmProductList:=TfrmProductList.Create(Application);
try
if grdList.SelectedField=dm.tPIncDetailPNo then
begin
if not dm.tPIncDetailPNo.IsNull then
frmProductList.PNo:=dm.tPIncDetail.FieldValues['PNo'];
if frmProductList.ShowModal=mrOK then
begin
qq.Close;
qq.SQL.Clear;
qq.SQL.Add('SELECT Count(PNo) AS CPNo FROM PIncDetail WHERE ID LIKE '''+
dm.tPIncMasterID.AsString+''' AND PNo LIKE '''+frmProductList.PNo+'''');
qq.Open;
if qq.FieldByName('CPNo').Value<1 then
begin
dm.tPIncDetail.Edit;
dm.tPIncDetail.FieldValues['PNo']:=frmProductList.PNo;
end
else
dm.tPIncDetail.Locate('PNo',frmProductList.PNo,[]);
end;
end;
finally
frmProductList.Free;
end;
end;

procedure TfrmIn.PickVendor;
begin
frmVendorList:=TfrmVendorList.Create(application);
try
if not dm.tPIncMasterVendor.IsNull then
frmVendorList.Vendor:=dm.tPIncMaster.FieldValues['Vendor'];
if frmVendorList.ShowModal=mrOK then
begin
dm.tPIncMaster.Edit;
dm.tPIncMaster.FieldValues['Vendor']:=frmVendorList.Vendor;
end;
finally
frmVendorList.Free;
end;
end;

procedure TfrmIn.grdListDblClick(Sender: TObject);
begin
acPickPNo.Execute;
end;

procedure TfrmIn.FormCreate(Sender: TObject);
begin
dm.tPDepots.Open;
Vendorlist:= TStringList.create;
VendorList.Sorted:=True;
VendorList.Duplicates:=dupignore;
if dm.tPVendors.Active=false then
dm.tPVendors.Open;
dm.tPVendors.First;
while not dm.tPVendors.Eof do
begin
VendorList.Add(dm.tPVendorsVendor.Value);
dm.tPVendors.Next;
end;
dm.tPVendors.Close;

grdList.Columns[0].PickList:=Nil;
dm.qProducts.Open;
dm.qProducts.First;
while not dm.qProducts.Eof do
begin
grdList.Columns[0].PickList.Add(DM.qProducts.FieldByName('PNo').AsString);
dm.qProducts.Next;
end;
dm.qProducts.Close;
end;

procedure TfrmIn.grdListKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (key=9) and (Shift = [ssCtrl]) then
begin
acPickPNo.Execute;
end;
end;

procedure TfrmIn.btnVendorClick(Sender: TObject);
begin
acPickVNC.Execute;
end;

procedure TfrmIn.edtVendorKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (key=9) and (Shift = [ssCtrl]) then
begin
acPickVNC.Execute;
end;
end;

procedure TfrmIn.edtVendorKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
theText: string;
i, p: integer;
begin
with edtVendor do
case key of
8, 13, 46, 37..40: ; // 如果是backspace, enter, delete, or arrows键,则不执行
else
begin
// 从开始的字符,搜索未选定的部分
p := selStart; // 指针位置
theText := copy(text, 0, p); // 排除搜索部分
// 匹配列表文本
for i := 0 to Vendorlist.count-1 do
begin
// 获取列表文本
if pos(upperCase(theText), upperCase(VendorList))=1 then
if compareText(theText, VendorList) < 0 then
begin
text := VendorList;
selStart := p;
SelLength := length(text) - selStart;
break; // 如果匹配,则退出
end;
end; // for
end; // case
end; // with
end;

procedure TfrmIn.FormDestroy(Sender: TObject);
begin
VendorList.Destroy;
dm.tPIncMaster.Close;
end;

procedure TfrmIn.acNewExecute(Sender: TObject);
begin
//此处加上操作权限的判断
//adqRights是用户权限表,而Append是“新增”权限的字段
// if (not isAdmin) and (not adqRightsAppend.AsBoolean) then
// raise Exception.Create('没有足够的权限执行本操作');
//当新增时,设单据为“编辑”状态
dm.isEditing:=True;
//设主表为新增状态
dm.tPIncMaster.Insert;
//设单据为“编辑”状态
dm.isEditing:=True;
end;

procedure TfrmIn.acEditExecute(Sender: TObject);
begin
//此处加上操作权限的判断
//adqRights是用户权限表,而Edit是“编辑”权限的字段
// if (not isAdmin) and (not adqRightsEdit.AsBoolean) then
// raise Exception.Create('没有足够的权限执行本操作');
//设“单据”为“编辑”状态
dm.isEditing:=True;
//设主表为“编辑”状态
sMaster.DataSet.Edit;
sDetail.DataSet.Edit;
end;

procedure TfrmIn.acCancelExecute(Sender: TObject);
begin
// if messagebox(application.Handle,'当前单据正在编辑中,是否确定取消?取消后将不能恢复!','警告',MB_YESNO+MB_DefButton2+MB_IconStop+MB_ApplModal)=IDNo then
// abort
// else
// begin
dm.tPIncDetail.Cancel;
dm.tPIncDetail.Requery();
dm.tPIncDetail.CancelBatch();
dm.isEditing:=False;
dm.tPIncMaster.Cancel;
// end;
end;

procedure TfrmIn.acSaveExecute(Sender: TObject);
begin
with DM do
begin
try
//BeforePost
if not conn.InTransaction then
conn.BeginTrans
else
raise Exception.Create('已经存在一个事务,在开始新的事务之前必须提交或回滚该事务.');
//Post
if tPIncDetail.State in dsEditModes then
tPIncDetail.Post;
isEditing:=False;
tPIncMaster.Post;
tPIncDetail.UpdateBatch();
//AfterPost
//计算合计数
//UpdateTotals(tPIncMaster,tPIncDetail);
if conn.InTransaction then
conn.CommitTrans;
isEditing:=False;
except
//PostError
if conn.InTransaction then
conn.RollbackTrans;
raise;
end;
end;
end;

procedure TfrmIn.acDelExecute(Sender: TObject);
begin
With DM do
begin
if messagebox(application.Handle,'是否确定删除该单据?删除后将不能恢复!','警告',MB_YESNO+MB_DefButton2+MB_IconStop+MB_ApplModal)=IDNo then
abort
else
begin
try
//BeforeDelete
//此处加上操作权限的判断
//adqRights是用户权限表,而Append是“删除”权限的字段
// if (not isAdmin) and (not adqRightsDelete.AsBoolean) then
// raise Exception.Create('没有足够的权限执行本操作');
if not conn.InTransaction then
conn.BeginTrans
else
raise Exception.Create('已经存在一个事务,在开始新的事务之前必须提交或回滚该事务.');
//Delete
adqDelete.Close;
adqDelete.SQL.Clear;
adqDelete.SQL.Add('DELETE PIncDetail WHERE ID=:ID');
adqDelete.DataSource:=sMaster;
adqDelete.ExecSQL;
tPIncMaster.Delete;
//AfterDelete
//计算合计数
//UpdateTotals(tPIncMaster,tPIncDetail);
if conn.InTransaction then
conn.CommitTrans;
isEditing:=False;
except
//DeleteError
if conn.InTransaction then
conn.RollbackTrans;
raise;
end;
end;
end;
end;

procedure TfrmIn.acFirstExecute(Sender: TObject);
begin
sMaster.DataSet.First;
end;

procedure TfrmIn.acPriorExecute(Sender: TObject);
begin
sMaster.DataSet.Prior;
end;

procedure TfrmIn.acNextExecute(Sender: TObject);
begin
sMaster.DataSet.Next;
end;

procedure TfrmIn.acLastExecute(Sender: TObject);
begin
sMaster.DataSet.Last;
end;

procedure TfrmIn.acPrintExecute(Sender: TObject);
begin
frp.LoadFromFile(DM.WPath+'In.frf');
frp.ShowReport;
end;

procedure TfrmIn.acExitExecute(Sender: TObject);
begin
close;
end;

procedure TfrmIn.sMasterDataChange(Sender: TObject; Field: TField);
begin
//如果主表在编辑或新增状态,且不为首记录,则前一记录按钮可用
acPrior.Enabled := (not sMaster.DataSet.Bof) and (not (sMaster.DataSet.State in [dsEdit, dsInsert]));
//如果前一记录按钮可用,且主表在编辑或新增状态,则首记录按钮可用
acFirst.Enabled := (acPrior.Enabled) and (not (sMaster.DataSet.State in [dsEdit, dsInsert]));
//如果主表在编辑或新增状态,且不为未记录,则后一记录按钮可用
acLast.Enabled := (not sMaster.DataSet.Eof) and (not (sMaster.DataSet.State in [dsEdit, dsInsert]));
//如果后一记录按钮可用,且主表在编辑或新增状态,则未记录按钮可用
acNext.Enabled := (acLast.Enabled) and (not (sMaster.DataSet.State in [dsEdit, dsInsert]));
//如果主表记录大于零,则删除按钮可用
acDel.Enabled := sMaster.DataSet.RecordCount > 0;
//如果主表在编辑或新增状态,则保存按钮可用
acSave.Enabled := sMaster.DataSet.State in [dsEdit, dsInsert];
//如果保存按钮可用,则取消按钮可用
acCancel.Enabled := acSave.Enabled;
//如果保存按钮不可用,则新增按钮可用
acNew.Enabled := not acSave.Enabled;
//如果保存按钮不可用,则打印按钮可用
acPrint.Enabled:=not acSave.Enabled;
//如果新增按钮可用,则编辑按钮可用
acEdit.Enabled := acNew.Enabled;
acPickVNC.Enabled:=acSave.Enabled;

//以下部分为核准部分
// AField := adqMain.FindField('ifapprove');
// if AField <> nil then
// acApprove.Enabled := (not AField.AsBoolean) and (adqMain.RecordCount > 0);
//如果子表与主表的关联字段不为空,且主表字段值与子表参数不同,
//则使子表参数值为主表该字段值
if (Field <> nil) and (Field.FieldName = dm.tPIncDetail.Parameters[0].Name) and (Field.Value <> dm.tPIncDetail.Parameters[0].Value) then
dm.tPIncDetail.Parameters[0].Value := Field.Value;
end;

procedure TfrmIn.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;

procedure TfrmIn.acNewDetailExecute(Sender: TObject);
begin
sDetail.DataSet.Insert;
end;

procedure TfrmIn.acCancelDetailExecute(Sender: TObject);
begin
sDetail.DataSet.Cancel;
end;

procedure TfrmIn.acDelDetailExecute(Sender: TObject);
begin
sDetail.DataSet.Delete;
end;

procedure TfrmIn.sDetailDataChange(Sender: TObject; Field: TField);
begin
acPickPNo.Enabled:= sDetail.DataSet.State in [dsEdit,dsInsert];
acCancelDetail.Enabled:=(sDetail.DataSet.State in [dsEdit,dsInsert]) and (not (sDetail.DataSet.Bof or sDetail.DataSet.Eof));
acDelDetail.Enabled:=acSave.Enabled;
acNewDetail.Enabled:=acSave.Enabled;
if acPickPNo.Enabled then
begin
grdList.Columns[0].ButtonStyle:=cbsAuto;
grdList.Columns[0].AutoDropDown:=True;
end
else
begin
grdList.Columns[0].ButtonStyle:=cbsNone;
grdList.Columns[0].AutoDropDown:=False;
end;
end;
 
oceanwave的办法可行
另外一种方法:
1、对主表,从表都是用内存表
2、保存时,执行一个存储过程,用事务实现你的逻辑
 
接受答案了.
 
顶部