/*查资料,发帖子总是没有找到满意的答复,一气之下,晚饭也没有吃
就抱着笔记本写这篇贴子.....今天想找一个正确的解决方法*/
一、问题的前期准备工作以及说明
1、环境:Windows Professional2000(SP3)+Delphi6+ADO2.6+MS SQL Server2000
2、操作类型:Master/Detail;创建主从数据表如下:
/*创建主表*/
Create table tMaster(
ncID nchar(20) PRIMARY KEY NONCLUSTERED,
dOptDate datetime not null default GetDate(),
cField01 char(10),
fField02 float not null default(0),
mField03 money not null default(0)
nOther char(10) null
)
/*创建从表*/
/*ncId,cDKeyFld 共同作为子表tDetail的主键值*/
CREATE TABLE tDetail (
ncID nchar(10) NOT NULL REFERENCES tMaster(ncID),
cDKeyFld char(10) NOT NULL ,
cdField02 char(10) NULL ,
cdField03 char(10) NULL
) ON [PRIMARY]
3、主从数据表的连接方式:
创建ADOQuery名称为“ADOQryM”
ADOQryM.SQL.Text:='select * from tMaster';
创建ADOQuery名称为“ADOQryD”
ADOQryD.SQL.Text:='select * from tDetail where ncID=:ncId';
4、在ADOQryM的AfterSroll事件中写如下代码:
with ADOQryDetail do
begin
Close;
Paramters.ParamByName('ncID').Value := QryADOM.FieldByName('ncID').AsString;
Open;
end;
5、书写添加数据、修改数据、取消操作、保存方法
//add new
function AddNew:Boolean;
begin
...
ADOQryM.Append;
....
end;
//edit current data
function EditCurr:Boolean;
begin
...
ADOQryM.Edit;
....
end;
//cancel updatebatch
procedure CancelOpt;
begin
...
ADOQryD.UpdateBatch(arAll);
ADOQryM.UpdateBatch(arAll);
...
end;
//save current operation
function Save:Boolean;
begin
....
ADOQryD.UpdateBatch(arAll);
ADOQryM.UpdateBatch(arAll);
....
end;
6、然后创建界面、添加数据集、数据显示控件、操作button.
完成上面主从数据表的updatabatch模式下的添加、修改、保存操作。 应用Delphi中的ADODataset的批处理(LockType=ltBatchOptimistic)
进行数据操作时,总是有这样的错误提示出现:1、当保存(调用Save方法)添加新数据、或者修改当前数据时,出现下面的错误提示:
“无法为更新行集定位:一些值可能已在读取后改变!”
2、当此时调用CancelOpt;(CancelUpdate)方法时,出现下面的错误提示
"行句柄应用了一个已被删除的行或被标示未删除的行!"对于上面这个错误我一直很头疼,我在处理主从表的时候,因为最终保存时需要检验数据的正确性
也就是在进行操作的时候不因为输入的错误而停止输入,而是把数据的检查方在了调用updateBatch
时。所以我试着把上面的数据表的主键都换成了自动增长的字段(分别添加一个字段autoId int).
就抱着笔记本写这篇贴子.....今天想找一个正确的解决方法*/
一、问题的前期准备工作以及说明
1、环境:Windows Professional2000(SP3)+Delphi6+ADO2.6+MS SQL Server2000
2、操作类型:Master/Detail;创建主从数据表如下:
/*创建主表*/
Create table tMaster(
ncID nchar(20) PRIMARY KEY NONCLUSTERED,
dOptDate datetime not null default GetDate(),
cField01 char(10),
fField02 float not null default(0),
mField03 money not null default(0)
nOther char(10) null
)
/*创建从表*/
/*ncId,cDKeyFld 共同作为子表tDetail的主键值*/
CREATE TABLE tDetail (
ncID nchar(10) NOT NULL REFERENCES tMaster(ncID),
cDKeyFld char(10) NOT NULL ,
cdField02 char(10) NULL ,
cdField03 char(10) NULL
) ON [PRIMARY]
3、主从数据表的连接方式:
创建ADOQuery名称为“ADOQryM”
ADOQryM.SQL.Text:='select * from tMaster';
创建ADOQuery名称为“ADOQryD”
ADOQryD.SQL.Text:='select * from tDetail where ncID=:ncId';
4、在ADOQryM的AfterSroll事件中写如下代码:
with ADOQryDetail do
begin
Close;
Paramters.ParamByName('ncID').Value := QryADOM.FieldByName('ncID').AsString;
Open;
end;
5、书写添加数据、修改数据、取消操作、保存方法
//add new
function AddNew:Boolean;
begin
...
ADOQryM.Append;
....
end;
//edit current data
function EditCurr:Boolean;
begin
...
ADOQryM.Edit;
....
end;
//cancel updatebatch
procedure CancelOpt;
begin
...
ADOQryD.UpdateBatch(arAll);
ADOQryM.UpdateBatch(arAll);
...
end;
//save current operation
function Save:Boolean;
begin
....
ADOQryD.UpdateBatch(arAll);
ADOQryM.UpdateBatch(arAll);
....
end;
6、然后创建界面、添加数据集、数据显示控件、操作button.
完成上面主从数据表的updatabatch模式下的添加、修改、保存操作。 应用Delphi中的ADODataset的批处理(LockType=ltBatchOptimistic)
进行数据操作时,总是有这样的错误提示出现:1、当保存(调用Save方法)添加新数据、或者修改当前数据时,出现下面的错误提示:
“无法为更新行集定位:一些值可能已在读取后改变!”
2、当此时调用CancelOpt;(CancelUpdate)方法时,出现下面的错误提示
"行句柄应用了一个已被删除的行或被标示未删除的行!"对于上面这个错误我一直很头疼,我在处理主从表的时候,因为最终保存时需要检验数据的正确性
也就是在进行操作的时候不因为输入的错误而停止输入,而是把数据的检查方在了调用updateBatch
时。所以我试着把上面的数据表的主键都换成了自动增长的字段(分别添加一个字段autoId int).
解决方案 »
- 在panel上有一个image组件,图片本身的背景是透明的,可是将这张图片放到image组件中,图片的背景却变成了白色,有一个白色的矩形框,怎样保持透明?
- sql语句中 那些字符串是怎么连接?
- 请教用delphi做系统监控程序的方法
- treeview如何表示它选中的项?
- 数据库路径问题
- 关于TXT直接在程序中打印的问题
- 使用dbexpress更新了多表数据,用ApplyUpdates方法时候总是出错,怎么解决?帮UP.
- 数组操作,请讨论
- 如何在dxdbgrid中保存数据库查出的数据
- 双击dbgrid选择一条记录问题
- 高分相送,如何用代码重画菜单为xp菜单!?
- 程序员兄弟,从昨天早上醒来,到昨晚睡觉.你一天都做了什么?有兴趣的回忆一下
ADODataset的批处理没有提到这样的错误。讲得太简单,无奈继续翻查ADO2.5程序员帮助文档,找到如下内容:/***********************************/
UpdateBatch 方法/***********************************/ 将所有挂起的批更新写入磁盘。语法recordset.UpdateBatch AffectRecords参数AffectRecords 可选。AffectEnum 值,指示 UpdateBatch 方法影响的
记录数目。说明当在批更新模式下修改 Recordset 对象时,请用 UpdateBatch 方法将在
Recordset对象中所作的所有更改传送到基本数据库。如果 Recordset 对象支持批更新,在调用 UpdateBatch 方法之前,
可以把对一个或多个记录所作的多个更改在本地缓存。
如果调用 UpdateBatch 方法时正在编辑当前记录或添加新记录,
那么在将批更改传送到提供者之前,ADO 将自动调用 Update 方法保
存对当前记录所作的所有挂起的更改。批更新应当只与键集游标或静态游标配合使用。注意 如果当前 Recordset 中看不到记录(如没有与过滤器相匹配的记录),
那么将此参数指定为 adAffectGroup 值将导致错误。如果由于与基本数据冲突(如记录已被另一用户删除)而导致对某个或所
有记录的更改传送失败,提供者将向 Errors 集合返回警告,并发生运行时错误。
用 Filter 属性 (adFilterAffectedRecords) 和 Status 属性来定位发生冲突的记录。要取消所有挂起的批更新,请使用 CancelBatch 方法。如果设置了 Unique Table 和 Update Resync 动态属性,
并且 Recordset 是对多个表执行 JOIN 操作得到的结果,
那么根据 Update Resync 属性的设置,Resync 方法将在
UpdateBatch 方法之后隐式地执行。在数据源中进行批更新时,各个更新的顺序不必与在本地
Recordset 中进行批更新的顺序相同。更新顺序取决于提
供者。编写相互关联的更新代码时请注意这一点,
如外键将约束插入或更新。
/***********************************/
CancelBatch 方法/***********************************/ 取消挂起的批更新。语法recordset.CancelBatch AffectRecords参数AffectRecords 可选。AffectEnum 值,指示 CancelBatch 方法影响的记
录数目。说明在批更新模式下,使用 CancelBatch 方法取消 Recordset 中任何挂起的更新。
如果 Recordset 处于立即更新模式,调用不带 adAffectCurrent 的CancelBatch
产生错误。
如果调用 CancelBatch 时在编辑当前记录或添加新记录,那么 ADO 先调用
CancelUpdate 方法以取消任何缓存的更改。然后取消 Recordset 中所有挂起的
更改。
有可能在 CancelBatch 调用后,特别是在添加新记录的过程中无法确定当前记录。
因此,在 CancelBatch 调用后应考虑将当前记录位置设置为Recordset 中的一个
已知位置。例如调用 MoveFirst 方法。如果因与基本数据冲突而导致取消挂起更新的尝试失败(如记录已被其他用户删除)
,提供者将向 Errors 集合返回警告但不终止程序执行。
只有在所有提出请求的记录上都发生冲突时才会发生运行时错误。用 Filter 属性
(adFilterAffectedRecords) 和 Status 属性来定位发生冲突的记录。
/****************************/
然后查找例子如下:
/****************************/
UpdateBatch 和 CancelBatch 方法范例 (VB)
本范例演示 UpdateBatch 和 CancelBatch 方法。Public Sub UpdateBatchX() Dim rstTitles As ADODB.Recordset
Dim strCnn As String
Dim strTitle As String
Dim strMessage As String ' Assign connection string to variable.
strCnn = "Provider=sqloledb;" & _
"Data Source=srv;Initial Catalog=Pubs;User Id=sa;Password=; " Set rstTitles = New ADODB.Recordset
rstTitles.CursorType = adOpenKeyset
rstTitles.LockType = adLockBatchOptimistic
rstTitles.Open "Titles", strCnn, , , adCmdTable
rstTitles.MoveFirst ' Loop through recordset and ask user if she wants
' to change the type for a specified title.
Do Until rstTitles.EOF
If Trim(rstTitles!Type) = "psychology" Then
strTitle = rstTitles!Title
strMessage = "Title: " & strTitle & vbCr & _
"Change type to self help?" If MsgBox(strMessage, vbYesNo) = vbYes Then
rstTitles!Type = "self_help"
End If
End If rstTitles.MoveNext
Loop ' Ask the user if she wants to commit to all the
' changes made above.
If MsgBox("Save all changes?", vbYesNo) = vbYes Then
rstTitles.UpdateBatch
Else
rstTitles.CancelBatch
End If ' Print current data in recordset.
rstTitles.Requery
rstTitles.MoveFirst
Do While Not rstTitles.EOF
Debug.Print rstTitles!Title & " - " & rstTitles!Type
rstTitles.MoveNext
Loop ' Restore original values because this is a demonstration.
rstTitles.MoveFirst
Do Until rstTitles.EOF
If Trim(rstTitles!Type) = "self_help" Then
rstTitles!Type = "psychology"
End If
rstTitles.MoveNext
Loop
rstTitles.UpdateBatch rstTitles.CloseEnd Sub 按照上面叙述的,进行批处理的时候应该跟数据表的字段设定无关,只要指定
数据表的主键值,保证数据的唯一性updatebatch就应该可以执行的啊?
请看下面这段话: ADO的BatchUpdate功能和BDE/IDAPI的CachedUpdate非常类似。它的工作原
理就是当ADO从数据源取得数据之后,客户端对于所有数据的修改都暂时储存在
客户端的缓存中,而不是立刻更新回数据源中。而当客户端决定要把所有的修改
更新回数据源时,才调用A D O的方法,把所有的修改更新回数据源中。
使用BatchUpdate方法来处理数据的好处是客户端和数据源之间不会产生密切
的互动,因此可以降低数据源的负荷。此外也可以减少网络的Roundtrip,这在拥
有大量客户端的应用系统中是非常有帮助的。此外由于BatchUpdate是把客户端对
于数据的修改暂时储存在客户端内存中,因此它对于数据的修改动作非常快速,只
在最后把所有的修改更新回数据源时才需要比较多的时间。不过使用BatchUpdate
也有一些问题,那就是程序员必须撰写较多的程序代码来处理数据更新错误的情形。
这是因为当客户端在修改数据时,可能已经有其他的用户改变了数据源中的数据,
因此当客户端把修改的数据更新回数据源时便可能会发生数据冲突或是错误的情
形。所以当程序员在使用BatchUpdate时,一定要搭配错误处理程序代码,才能够
撰写出安全坚固的应用程序。在本书稍后的章节中会讨论如何在ADO应用程序中
处理错误的情形。---摘自 Delphi 5.x ADO/MTS/COM+高级程序设计篇 根据ADO的BatchUpdate的处理原理,像上面得BatchUpdate操作(
单独用户独占式连接)应该时没问题的,但是为什么频繁发生这样的异常错误呢?
是ADO驱动程序的问题,还是MS SQL Server的问题?大家帮我看看吧?
非常感谢!非常感谢!非常感谢!
CoursorType 设为 ctKeyset 或 ctStatic , LockType 设为 ltBatchOptimistic看看行不行
这些设置肯定要的。
Up~~~~~~~~~~~~~~~~~~``
谢谢大家,帮我Up~~~~~~~~~~~正在等待,捉摸答案~~~~~~~~~~~
不要用adodataset
的异常引起的。“键列信息不足或者不正确。更新影响到过多的行”我明明
修改后的数据在数据表只有一条,并却主键信息足以满足修改的条件,
但是还是出现这个错误。另外我写了一个小的批处理程序,大家需要看看的话,
我发给你。希望和高手共同把这个问题解决了。
同时我在进行批处理操作的时候,设置了默认值也没有问题,但是我增加了一个
Insert触发器就不行了,老是提示错误信息。大家有兴趣的话,共同探讨。我已经
搞了一周了。翻了很多东西,但是帮助不大。