如何使用Delphi FireDAC对数据库应用UNIQUE约束来应用缓存更新FD
当delta包含对数据库具有UNIQUE约束的字段时,我有一个问题来解决缓存更新.我有一个具有以下DDL架构的数据库(内存中的SQLite可用于重现):
create table FOO ( ID integer primary key,DESC char(2) UNIQUE ); 初始数据库表包含一个ID = 1且DESC = R1的记录 使用TFDQuery(从FOO中选择*)访问此表,如果执行以下步骤,将使用ApplyUpdates正确应用生成的增量: >将记录ID = 1更新为DESC = R2 Delta包括以下内容: > R2 ApplyUpdates不会生成错误,因为delta上的第一个操作将是更新.第二个是插入.由于记录1现在是R2,因此可以完成插入,因为在此事务中没有违反唯一约束. 现在,执行以下步骤将生成完全相同的delta(查看FDQuery.Delta属性),但将生成UNIQUE约束违例. >使用DESC = TT附加新的临时记录ID = 2 Delta包括以下内容: > R2 请注意,FireDAC在两种情况下都会生成相同的增量,可以通过FDquery的Delta属性查看. 此步骤可用于重现错误: 文件>新的VCL表格申请;在表单上删除FDConnection和FDQuery;设置FDConnection以使用SQLite驱动程序(在内存数据库中使用);在表单上删除两个按钮,一个用于重现正确的行为,另一个用于重现错误,如下所示: 按钮确定: procedure TFrmMain.btnOkClick(Sender: TObject); begin // create the default database with a FOO table con.Open(); con.ExecSQL('create table FOO' + '(ID integer primary key,DESC char(2) UNIQUE)'); // insert a default record con.ExecSQL('insert into FOO values (1,''R1'')'); qry.CachedUpdates := true; qry.Open('select * from FOO'); // update the first record to T2 qry.First(); qry.Edit(); qry.Fields[1].AsString := 'R2'; qry.Post(); // append the second record to T1 qry.Append(); qry.Fields[0].AsInteger := 2; qry.Fields[1].AsString := 'R1'; qry.Post(); // apply will not generate a unique constraint violation qry.ApplyUpdates(); end; 按钮错误: // create the default database with a FOO table con.Open(); con.ExecSQL('create table FOO' + '(ID integer primary key,DESC char(2) UNIQUE)'); // insert a default record con.ExecSQL('insert into FOO values (1,''R1'')'); qry.CachedUpdates := true; qry.Open('select * from FOO'); // append a temporary record (TT) qry.Append(); qry.Fields[0].AsInteger := 2; qry.Fields[1].AsString := 'TT'; qry.Post(); // update R1 to R2 qry.First(); qry.Edit(); qry.Fields[1].AsString := 'R2'; qry.Post(); qry.Next(); // update TT to R1 qry.Edit(); qry.Fields[1].AsString := 'R1'; qry.Post(); // apply will generate a unique contraint violation qry.ApplyUpdates(); 解决方法
更新自编写此答案的原始版本以来,我已经做了一些调查,并开始认为在FireDAC支持Sqlite(至少在西雅图),或者我们不是,在ApplyUpdates等方面存在问题正确使用FD组件.它需要FireDAC的作者(这里是一个贡献者)来说明它是什么.
暂且不谈ApplyUpdates业务,您的代码还存在许多其他问题,即数据集导航会假设qry中行的排序及其Fields的编号. 我使用的测试用例是使用包含单行的Foo表启动(在执行应用程序之前) (1,'R1') 然后,我执行以下Delphi代码,同时使用外部应用程序(FireFox的Sqlite Manager插件)监视Foo的内容.代码执行时没有在应用程序中报告错误,但请注意它不会调用ApplyUpdates. Con.Open(); Con.StartTransaction; qry.Open('select * from FOO'); qry.InsertRecord([2,'TT']); assert(qry.Locate('ID',1,[])); qry.Edit; qry.FieldByName('DESC').AsString := 'R2'; qry.Post; assert(qry.Locate('ID',2,[])); qry.Edit; qry.FieldByName('DESC').AsString := 'R1'; qry.Post; Con.Commit; qry.Close; Con.Close; 在Con.Close执行之后,外部应用程序看不到添加的行(ID = 2),我觉得这很令人费解.一旦调用了Con.Close,外部应用程序就会将Foo显示为包含 (1,'R2') (2,'R1') 但是,如果我调用ApplyUpdates,我无法避免约束违规错误,无论我对代码做出任何其他更改,包括在第一个Post之后添加对ApplyUpdates的调用. 所以,在我看来,ApplyUpdates的操作有缺陷或者没有正确使用. 我提到了FireDAC的作者.他的名字是德米特里·阿雷菲耶夫(Dmitry Arefiev),他在SO上回答了很多关于他的问题,尽管在过去的几个月左右我没有在这里注意到他.您可以尝试通过在EMBA的FireDAC NG论坛https://forums.embarcadero.com/forum.jspa?forumID=502中发帖来吸引他的注意力. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |