为什么分布式又出错!(200分)

  • 主题发起人 主题发起人 3p
  • 开始时间 开始时间
3

3p

Unregistered / Unconfirmed
GUEST, unregistred user!
我使用ADO+MTS+MIDAS编写系统,在前台修改发生奇怪现象,
插入数据没有问题,修改第一次没问题,修改第二次同一记录发生了“record changed
by another user”错误,然后关闭程序,再次修改还是那个错误,以后此记录再也无法修改
那位遇过同样的问题?请指点!谢谢!
数据库采用MS SQL2000,以前使用MS SQL7也发生了类似的问题,
我曾考虑是否应设置DatasetProvider的Updatemode=updatewherekeyonly,然后在设置
datasetprovider.beforeupdaterecord事件中设定keyfield,但却得到keyfield
not found的错误,如何是好?我现在只能设定updatewhereall,但这有关系吗?
  恳请各位发表高论。
  我是在单机Server上编写程序,没有连接网络!
 
记得去年七月份我也遇到了这个问题,试了很多次,觉得应该与Updatemode无关。
我的解决办法是,不使用ApplyUpdate自动更新功能,而是在服务器端的DataSetProvider
的BeforeUpdateRecord中手工把Delta更新到数据库。以后就再也没有类似问题了。
这样做的一个附带好处是,还可以在服务器端对数据进行更改和检测。如果做一个
自动生成提交数据更新SQL语句的子程序,就会觉得这种方法不烦琐,挺值得的。
{******************************************************************************
生成查询语句
入口: DataName: 数据表名称
SourceFields: 数据表的字段名列表,如:'编号;名称;...;备注'
DeltaFields: 包含要修改的数据的数据表的字段名列表
WhereFields: 作为条件的字段名列表
WhereValues: 作为条件的字段的数值
SourceQuery: 用于运行查询语句的Query组件
DeltaDS: 包含要修改的数据的数据表
UpdateKind: ukModify => 修改查询, ukInsert => 新增查询
生成后的查询语句在 SourceQuery 的 SQL 属性中, 执行 ExecSQL 即可
*******************************************************************************}
procedure GenerateSQL(DataName, SourceFields, DeltaFields, WhereFields:string;
WhereValues:OleVariant;
SourceQuery:TADOQuery;
DeltaDS:TDataSet;
UpdateKind: TUpdateKind);
var
i, ValueCount, j, k: integer;
SourceFieldList, DeltaFieldList, WhereFieldList: TStringList;
s: string;
begin
SourceFieldList := TStringList.Create;
DeltaFieldList := TStringList.Create;
WhereFieldList := TStringList.Create;
TextToList(WhereFields, WhereFieldList);
// 如果 更新字段列表 为空, 自动生成
if SourceFields='' then
begin
for i:=0 to DeltaDS.FieldCount-1do
begin
s := DeltaDS.Fields.FieldName;
// 跳过非正常字段
if DeltaDS.Fields.DataType in [ftUnKnown, ftAutoInc, ftParadoxOle, ftDBaseOle, ftADT, ftArray, ftArray,
ftReference, ftDataSet, ftOraBlob, ftOraClob, ftVariant, ftInterface, ftIDispatch] then
Continue;
if UpdateKind = ukModify then
// 更新操作,不包含关键字段
if WhereFieldList.IndexOf(s)>=0 then
Continue;
// 是关键字段,不加入更新字段列表
SourceFields := SourceFields + s + ';';
end;
// 删除最后一个 "分号"
if Length(SourceFields)>0 then
SourceFields := Copy(SourceFields, 1, Length(SourceFields)-1);
DeltaFields := SourceFields;
end;

if DeltaFields='' then
DeltaFields := SourceFields;
TextToList(SourceFields, SourceFieldList);
TextToList(DeltaFields, DeltaFieldList);
if SourceFieldList.Count <> DeltaFieldList.Count then
raise Exception.Create('SQL 语句设置中的数据更新与数据源的字段数目不一致');
SourceQuery.SQL.Clear;
try
if UpdateKind = ukModify then
begin
SourceQuery.SQL.Add('Update ' + DataName + ' Set ');
ValueCount := 0;
for i:=0 to SourceFieldList.Count-1do
begin
if DeltaDS.FieldByName(DeltaFieldList).IsNull then
Continue;
s := SourceFieldList + '=:DeltaField' + InttoStr(i);
if ValueCount>0 then
s := ', ' + s;
SourceQuery.SQL.Add(s);
Inc(ValueCount);
end;
if ValueCount=0 then
begin
SourceQuery.SQL.Clear;
Exit;
end;

if WhereFieldList.Count>0 then
SourceQuery.SQL.Add(' Where ');
for i:=0 to WhereFieldList.Count-1do
begin
s := ' ' + WhereFieldList + '=:WhereField' + InttoStr(i);
if i<(WhereFieldList.Count -1) then
s := s + ' And ';
SourceQuery.SQL.Add(s);
end;

SourceQuery.Parameters.ParseSQL(SourceQuery.SQL.Text, True);
for i:=0 to ValueCount-1do
begin
s := SourceQuery.Parameters.Items.Name;
Delete(s, 1, 10);
Val(s, j, k);
SourceQuery.Parameters.Items.Value :=
DeltaDS.FieldByName(DeltaFieldList[j]).Value;
end;
for i:=0 to WhereFieldList.Count-1do
begin
SourceQuery.Parameters.Items[i + ValueCount].Value :=
WhereValues;
end;
end;

if UpdateKind = ukInsert then
begin
SourceQuery.SQL.Add('Insert into ' + DataName + ' (');
ValueCount := 0;
for i:=0 to SourceFieldList.Count-1do
begin
if DeltaDS.FieldByName(DeltaFieldList).IsNull then
Continue;
s := ' ' + SourceFieldList;
if ValueCount>0 then
s := ', ' + s;
SourceQuery.SQL.Add(s);
Inc(ValueCount);
end;
if ValueCount=0 then
begin
SourceQuery.SQL.Clear;
Exit;
end;

SourceQuery.SQL.Add(') Values (');
ValueCount := 0;
for i:=0 to SourceFieldList.Count-1do
begin
if DeltaDS.FieldByName(DeltaFieldList).IsNull then
Continue;
s := ':DeltaField' + InttoStr(i);
if ValueCount>0 then
s := ', ' + s;
SourceQuery.SQL.Add(s);
Inc(ValueCount);
end;
SourceQuery.SQL.Add(') ');
SourceQuery.Parameters.ParseSQL(SourceQuery.SQL.Text, True);
for i:=0 to ValueCount-1do
begin
s := SourceQuery.Parameters.Items.Name;
Delete(s, 1, 10);
Val(s, j, k);
SourceQuery.Parameters.Items.Value :=
DeltaDS.FieldByName(DeltaFieldList[j]).Value;
end;
end;
finally
SourceFieldList.Free;
DeltaFieldList.Free;
WhereFieldList.Free;
end;
end;

{**************************************************************************************************
把用分号分隔的字符串转变为一个 StringList
入口: s -> 用分号分隔的字符串;
出口: SList -> 转变后的 StringList
***************************************************************************************************}
procedure TextToList(s: string;
var SList: TStringList);
var
i: integer;
begin
SList.Clear;
i := Pos(';', s);
While i>0do
begin
SList.Add(Copy(s, 1, i-1));
Delete(s, 1, i);
i := Pos(';', s);
end;
SList.Add(s);
end;

 
修改第一次, refrushrecord;
 
问题出在您的ADOConnection上。我原来也遇到此问题,后来调整了ADOConnection就没事了
 
非也,问题的暂时解决是:在datasetprovidder的onupdatedat的event中指定keyfiled
这样可以免去自己编程的烦恼,问题看上去解决了,但当应用少量取数据应用时,问题又
发生了,是这样的:按李维书上的例子,在adoquery的sql中指定select top n ... where
recno>:m ....这里recno即keyfield,在clientdataset和datasetprovider中利用before
getrecords事件的Ownerdata传递参数m,从而达到所谓的每次取少量的数据,取出的数据
appenddata到客户端,事实上查询成功了,但修改数据时有再次发生了record changed
by anotheruser!的错误,很烦咧!为什么?由谁试过成功的?来呀!来呀!

 
多人接受答案了。
 

Similar threads

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