FireDAC Append函数未创建新记录反而修改已有记录求助
问题排查:C++Builder 12下FireDAC+SQLite的Append()异常问题
问题背景
使用C++Builder 12开发Windows平台的简易CRUD应用,采用SQLite数据库与FireDAC组件。应用包含两个主菜单,其中第二个主菜单存在异常:
- 点击“nouvelle rallonge”(新延长件)或“nouveau tube”(新管件)按钮时,调用对应窗口执行
Append()+Post()操作 - 预期行为:创建新数据库记录
- 实际异常:未生成新条目,反而修改DBGrid中显示的现有记录
- 其他页面采用相同窗口架构(基于TDBEdit)和代码逻辑,运行完全正常
相关代码
第二主页面代码
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "menuApp.h" #include "menuRallonges.h" #include "datamodule.h" #include "gestionRallonge.h" #include "gestionTube.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TFMenuRallonges *FMenuRallonges; extern bool isEditing; //--------------------------------------------------------------------------- __fastcall TFMenuRallonges::TFMenuRallonges(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::btRallongeClick(TObject *Sender) { TFRallonge *FRallonge = new TFRallonge(this); short res = FRallonge->ShowModal(); delete FRallonge; } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::btTubeClick(TObject *Sender) { TFTube *FTube = new TFTube(this); short res = FTube->ShowModal(); delete FTube; } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::FormShow(TObject *Sender) { DataModule1 = new TDataModule1(this); isEditing=false; DBGrid1->DataSource->DataSet->Refresh(); DBGrid2->DataSource->DataSet->Refresh(); } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::btModifRallongeClick(TObject *Sender) { isEditing=true; btRallongeClick(this); FormShow(this); } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::btModifTubeClick(TObject *Sender) { isEditing=true; btTubeClick(this); FormShow(this); } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::FormDestroy(TObject *Sender) { if (DataModule1 != nullptr) { delete DataModule1; DataModule1 = nullptr; } } //--------------------------------------------------------------------------- void __fastcall TFMenuRallonges::FormClose(TObject *Sender, TCloseAction &Action) { FormDestroy(this); } //---------------------------------------------------------------------------
管件页面代码
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "datamodule.h" #include "menuRallonges.h" #include "gestionTube.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TFTube *FTube; extern bool isEditing; //--------------------------------------------------------------------------- __fastcall TFTube::TFTube(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TFTube::Button1Click(TObject *Sender) { Button1->SetFocus(); try { DataModule1->TubevideTable->Post(); } catch (const Exception &E) { ShowMessage("Erreur lors de l'insertion : " + E.Message); } } //--------------------------------------------------------------------------- void __fastcall TFTube::FormShow(TObject *Sender) { if (isEditing==true) { // ShowMessage("editing true"); } else { // ShowMessage("editing false"); // DataModule1->TubevideTable->Last(); DataModule1->TubevideTable->Append(); } } //--------------------------------------------------------------------------- void __fastcall TFTube::Button2Click(TObject *Sender) { DataModule1->TubevideTable->Cancel(); } //---------------------------------------------------------------------------
问题原因排查及修复建议
1. DataModule重复创建导致数据集实例冲突
第二主页面的FormShow方法中,每次页面显示都会新建DataModule1实例:
DataModule1 = new TDataModule1(this);
这会导致:
- 当前操作的数据集(管件/延长件窗口中调用的)是新DataModule的实例
- DBGrid绑定的是旧DataModule的数据集实例
- 视觉上看到“修改现有记录”,实际是新数据集默认指向第一条记录并进入编辑状态,而DBGrid未同步新数据集的内容
修复:
- 改为在应用启动时初始化全局DataModule,避免重复创建
- 或确保所有页面共享同一个DataModule实例,不在
FormShow中重复实例化
2. 全局变量isEditing的竞态问题
修改按钮点击后,先设置isEditing=true,调用窗口后立即执行FormShow重置isEditing=false,可能导致管件窗口的FormShow执行时,isEditing已经被重置为false,逻辑判断出错。
修复:
- 移除全局变量
isEditing,改为通过窗口构造函数传递参数的方式传递编辑状态:// 修改管件窗口的构造函数 class TFTube : public TForm { private: bool fIsEditing; public: __fastcall TFTube(TComponent* Owner, bool editing); // ... }; __fastcall TFTube::TFTube(TComponent* Owner, bool editing) : TForm(Owner), fIsEditing(editing) { } // 调用窗口时传递参数 void __fastcall TFMenuRallonges::btTubeClick(TObject *Sender) { bool editing = (Sender == btModifTube); // 根据按钮判断编辑状态 TFTube *FTube = new TFTube(this, editing); short res = FTube->ShowModal(); delete FTube; }
3. 数据集状态未正确重置
执行Append()前,若数据集处于编辑状态(比如之前未提交的修改),Append()可能不会创建新记录,而是继续编辑当前记录。
修复:
在Append()前添加状态检查,确保数据集处于浏览状态:
void __fastcall TFTube::FormShow(TObject *Sender) { if (fIsEditing) { // 编辑逻辑 } else { if (DataModule1->TubevideTable->State != dsBrowse) DataModule1->TubevideTable->Cancel(); DataModule1->TubevideTable->Append(); } }
4. DBGrid与数据集的绑定验证
检查第二主页面的DBGrid的DataSource是否正确绑定到DataModule的对应数据集,重复创建DataModule会导致绑定失效,DBGrid显示旧数据,造成操作错觉。
验证:
在FormShow中添加代码,确认DBGrid绑定的数据集与操作的数据集是同一个实例:
ShowMessage(DBGrid2->DataSource->DataSet->Name == DataModule1->TubevideTable->Name ? "绑定正确" : "绑定异常");
内容的提问来源于stack exchange,提问作者Alan Finiti
相关产品推荐
相关产品推荐

