大概各位在使用MIDAS的时候都会遇到这样一个问题,很是不明白。
以前我也一直不明白,直到今天,才多少有一些清除是为什么:明明没有别的用户修改数据,为什么会说数据已经被修改了呢?而当你在修改后再刷新一次就不会出现这样的问题了呢?其实,报:record has been changed by an other user一点都没有错!这个修改者不是别人,正是数据库本身!!!如果你使用SQL SERVER,你可以用事件探查器跟踪所有的SQL语句。解决这个问题的最关键是:Update产生的SQL语句的WHERE条件!如果你设定DataSetProvider的更新模式是updateWhereAll,那么你所有的字段都用来作为WHERE的搜索条件!!如果更新模式是updateKeyOnly,那么使用键值字段作为WHERE的搜索条件。关键是:如果在添加记录时候,某些字段是数据库自动产生的,最典型的是ID字段,自动增长,那么中间层可以获取新增记录的ID,但是,这个值并不会传回给ClientDataSet!!!!!!!!!!!!!!!!!然而,如果ClientDataSet的更新语句中使用了数据库自动更改的字段,那么所产生的SQL语句的WHERE部分必然是不对的!!!!ClientDataSet会和中间层的AdoDataSet(如果使用ADO)比较数据,因为AdoDataSet已经从数据库获取了数据库自动更新过的字段,但是ClientDataSet没有,所以两边比较不匹配!从而会出现“Record has been changed by another user”的错误!使用触发器也会出现这样的问题!!解决方法:我还没有想到最好的方法,但是有一点是可以肯定的:在自动产生的WHERE条件中不能含有数据库自动更新的字段。如ID由数据库自动产生,那么,就不要让他自动产生。
以前我也一直不明白,直到今天,才多少有一些清除是为什么:明明没有别的用户修改数据,为什么会说数据已经被修改了呢?而当你在修改后再刷新一次就不会出现这样的问题了呢?其实,报:record has been changed by an other user一点都没有错!这个修改者不是别人,正是数据库本身!!!如果你使用SQL SERVER,你可以用事件探查器跟踪所有的SQL语句。解决这个问题的最关键是:Update产生的SQL语句的WHERE条件!如果你设定DataSetProvider的更新模式是updateWhereAll,那么你所有的字段都用来作为WHERE的搜索条件!!如果更新模式是updateKeyOnly,那么使用键值字段作为WHERE的搜索条件。关键是:如果在添加记录时候,某些字段是数据库自动产生的,最典型的是ID字段,自动增长,那么中间层可以获取新增记录的ID,但是,这个值并不会传回给ClientDataSet!!!!!!!!!!!!!!!!!然而,如果ClientDataSet的更新语句中使用了数据库自动更改的字段,那么所产生的SQL语句的WHERE部分必然是不对的!!!!ClientDataSet会和中间层的AdoDataSet(如果使用ADO)比较数据,因为AdoDataSet已经从数据库获取了数据库自动更新过的字段,但是ClientDataSet没有,所以两边比较不匹配!从而会出现“Record has been changed by another user”的错误!使用触发器也会出现这样的问题!!解决方法:我还没有想到最好的方法,但是有一点是可以肯定的:在自动产生的WHERE条件中不能含有数据库自动更新的字段。如ID由数据库自动产生,那么,就不要让他自动产生。
解决方案 »
- 关于dll里窗口的问题!
- 请问installshield express for delphi 5可以为[用delphi 7作的软件]做安装软件么?
- 如何在sql2000里將其中一部分數据剪切出來喲
- ttreeview控件的使用。
- 我用SQL进行数据库编辑的时候 文本的数据没有问题 可是一碰到图片的数据 就会被破坏 这是为什么呀?
- 如何在库中查找重名的记录呢?请大家帮帮忙.............[20]
- 救命呀!,实在玩不转了,一个极简单的setrange的问题(牛虻)
- 关于DCOM。
- 有谁知道适合DELPHI用的UML,最好有介绍
- 急问 Dephi7 的局部变量问题
- 用过WPE的DELPHI高手来帮忙看看~~~
- 大虾们,来,进来参观一下,帮小弟解决一个问题!
说得不明确啊, 怎样得到? 中间层实现上在 UpdateRecord(注意是Record)后是不会知道自动 ID 的值的, 实际上是自增长ID 可以在 AfterUpdateRecord 上写到 SELECT MAX(ID) AS MAX_ID FROM TABLE 得到, 这时因为你的事务, 所以得到的值一定要是刚才加入的那条的ID, 但得到这个东东有什么意义, 看2..2. 这个值并不会传回给ClientDataSet?
回答是可以回伟给 cds 的, 在 dsp 的 Options 中 poPropogateChanges 设成 true, ok, 在 1 中的 AfterUpdateRecord 中写以 DeltaDS.FieldByName('ID').NewValue = MaxID, 你在客户机看看, ID 是不是回传了3. "ClientDataSet会和中间层的AdoDataSet(如果使用ADO)比较数据,因为AdoDataSet已经从数据库获取了数据库自动更新过的字段" 这句说得问题最大了!!!
你在认真观察一下在 Update 全过程中 AdoDataSet 是不是有被 Open 过...答案是没有!!!一个没有被打开的数据集怎样得到更新后的字段? Midas(现在的Datasnap) 是通过一个 TSQLResolver 分析Query, Table中的语句生成那几个(update, delete, insert)语句的, OldValue和NewValue由Delta包中带回, 所有更新的过程跟数据集没有任何关系
begin
end
else UpdateMode = ukModify ...
...
ssql: String;
MaxID: Integer;
begin
If UpdateKind=ukInsert then
begin
ssql := 'SELECT MAX(ID) MAX_ID FROM TEST01';
With AdoQry do
begin
Close;
SQL.Clear;
SQL.Add(ssql);
Open;
end;
MaxID := AdoQry.FieldByName('MAX_ID').AsInteger;
DeltaDS.FieldByName('ID').NewValue := MaxID;
end;
end;
这样确实是可以获取自动增长的ID,这样可以解决record changed by ....的问题。但是我发现了一个问题:
如果AdoConnection的KeepConnection设为False,那么在执行到 SQL.Add(ssql) 的时候,会报错:“在事务处理过程中中,连接对象不能显式的被断开”什么的,不知道是为什么。但是如果KeepConnection为True,则没有这个问题。不知道是什么原理?