我在两张桌子之间有一个主要的细节关系。Troq是主表,Troq_Alma是细节表。Troq_Alma主键由Troq主键(Troq.cod)和"Num_Orden“组成。这个"Num_Orden“字段不仅是表的PK的一部分,而且是一个Troq的几个Almas中的特定阿尔马的优先级。(Troq_Alma是将不同的Troq与其相关的Alma的表联系起来的表)
在某一点上,用户需要修改这个优先级,因此修改一组记录的主键(与一个特定的troq相关的almas集)。在表单中,有两个按钮(自旋按钮)与一个TDBGrid相关。如果我按下"Up“按钮,选中的Troq_Alma应该将"Num_Orden”减少1,而在"Num_Orden“中该值的Troq_alma将其值增加1。因此,在dbgrid中的表的”图像“中,没有重复的键。
当然,当我应用这个更新时:TFDQ_Troq_Alma.ApplyUpdates(-1);
我得到了重复的密钥错误,我发现这是非常符合逻辑的,因为在任何情况下,firedac都会尝试进行此更新,第一次修改将抛出重复的密钥错误,直到对之前拥有该主键的另一条记录进行修改,即它仍然拥有该主键。
我真的不知道这个问题是否有“公平”的解决方案,我想象的唯一一件事就是先为一个特定的Troq添加一些"num_orden“,然后再更新原来修改过的值,这是一项非常奇怪的工作,但是,根据我对delphi和firedac的了解,我真的找不到任何其他方法来解决这个问题。
使用Delphi XE6对Postgres 11.8数据库进行缓存更新,使用firedac。
如果可能引起任何兴趣,下面是两个旋转按钮(向上和向下)的代码:
procedure TFRM_Mant_TROQ.SpinBut_Troq_AlmaDownClick(Sender: TObject);
var iValActNumOrd, iValNumOrd2 : Integer;
RegActual: TBookMark;
iValMax: Integer;
begin
RegActual := DM_Mant_Troq.FDQ_Troq_Alma.GetBookmark;
iValMax := DM_DatosComun.MaxVal_FDQ(DM_Mant_Troq.FDQ_Troq_Alma, 'num_orden');
DM_Mant_Troq.FDQ_Troq_Alma.GotoBookmark(RegActual);
iValActNumOrd := DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value;
if iValActNumOrd < iValMax then begin
DM_Mant_Troq.FDQ_Troq_Alma.Next;
iValNumOrd2 := DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value;
DM_Mant_Troq.FDQ_Troq_Alma.Edit;
DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value := iValActNumOrd;
// DM_Mant_Troq.FDQ_Troq_Alma.Post;
DM_Mant_Troq.FDQ_Troq_Alma.GotoBookmark(RegActual);
DM_Mant_Troq.FDQ_Troq_Alma.Edit;
DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value := iValNumOrd2;
DM_Mant_Troq.FDQ_Troq_Alma.Post;
end;
end;
procedure TFRM_Mant_TROQ.SpinBut_Troq_AlmaUpClick(Sender: TObject);
var iValActNumOrd, iValNumOrd2 : Integer;
RegActual: TBookMark;
iValMin: Integer;
begin
RegActual := DM_Mant_Troq.FDQ_Troq_Alma.GetBookmark;
iValMin := DM_DatosComun.MinVal_FDQ(DM_Mant_Troq.FDQ_Troq_Alma, 'num_orden');
DM_Mant_Troq.FDQ_Troq_Alma.GotoBookmark(RegActual);
iValActNumOrd := DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value;
if iValActNumOrd > iValMin then begin
DM_Mant_Troq.FDQ_Troq_Alma.Prior;
iValNumOrd2 := DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value;
DM_Mant_Troq.FDQ_Troq_Alma.Edit;
DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value := iValActNumOrd;
DM_Mant_Troq.FDQ_Troq_Alma.GotoBookmark(RegActual);
DM_Mant_Troq.FDQ_Troq_Alma.Edit;
DM_Mant_Troq.FDQ_Troq_Alma.FieldByName('NUM_ORDEN').Value := iValNumOrd2;
DM_Mant_Troq.FDQ_Troq_Alma.Post;
end;
end;
这段代码可能会得到改进,但正如我提到的,我相信这段代码运行良好,我的观点是如何指示firedac“最终避免”这种独特的键验证。
实际上,Troq.Cod,Num_Orden不是表Troq_Alma的主键,但是在这两个字段上有一个唯一的索引,而且出于数据库完整性的目的,我非常喜欢这个惟一的索引。
发布于 2021-07-22 17:58:34
如果我们承认您有一个很好的理由来更改唯一的密钥,那么您需要确保您避免了密钥冲突。看起来,您正在处理本地缓存在TFDQuery
中的数据,然后应用更新。
这种方法的问题是,TFDQuery
会记住字段的加载值和当前值,因此您的中间更改将丢失,从而导致关键冲突。
避免这一问题的一个快速方法是在每次更改后使用ApplyUpdate
。如果您远离主店,这可能会给您带来问题。
如果需要为索引字段分配临时值,则需要确保该值是唯一的。如果数据模式允许,则只需否定Integer字段的值(如果未将其定义为无符号)。尽管可能会有另一条带有该值的记录,但如果您的约定只是暂时分配这些值,则应该避免关键冲突。
https://stackoverflow.com/questions/68487451
复制相似问题