我将Firebird数据库的内容显示到TDBgrid中。数据库有一个“ TIMESTAMP”数据类型字段,我想以日期/时间格式显示: 'YYYY / MM / DD HH:mm:ss'。 (现在显示为“ YYMMDD HHmmss”)
如何实现?
我尝试过:
procedure TDataModule1.IBQuery1AfterOpen(DataSet: TDataSet);
begin
TDateTimeField(IBQuery1.FieldByName('timestamp_')).DisplayFormat := 'YYYY/MM/DD HH:mm:ss';
end;
但是,这在程序的其他部分会引起一些副作用,因此它不是替代方法。例如,在“ IBQuery1.Open”语句中,我通过清除数据库的方法得到了“ ... timestamp_ not found ...”调试器消息。
function TfrmLogger.db_events_clearall: integer;
begin
result := -1;
try
with datamodule1.IBQuery1 do begin
Close;
With SQL do begin
Clear;
Add('DELETE FROM MEVENTS')
end;
if not Prepared then
Prepare;
Open; //Exception here
Close;
Result := 1;
end;
except
on E: Exception do begin
ShowMessage(E.ClassName);
ShowMessage(E.Message);
Datamodule1.IBQuery1.close;
end;
end;
end;
当尝试打开查询以写入数据库时,我收到相同的异常消息。
*编辑>>
我对数据库进行了如下修改:
function TfrmLogger.db_events_clearall: integer;
var
IBQuery: TIBQuery;
IBTransaction: TIBTransaction;
DataSource: TDataSource;
begin
result := -1;
//Implicit local db objects creation
IBQuery := TIBQuery.Create(nil);
IBQuery.Database := datamodule1.IBdbCLEVENTS;
DataSource := TDataSource.Create(nil);
DataSource.DataSet := IBQuery;
IBTransaction := TIBTransaction.Create(nil);
IBTransaction.DefaultDatabase := datamodule1.IBdbCLEVENTS;
IBQuery.Transaction := IBTransaction;
try
with IBQuery do begin
SQL.Text := DELETE FROM MSTEVENTS;
ExecSQL;
IBTransaction.Commit;
result := 1;
end;
except
on E : Exception do
begin
ShowMessage(E.ClassName + ^M^J + E.Message);
IBTransaction.Rollback;
end;
end;
freeandnil(IBQuery);
freeandnil(DataSource);
freeandnil(IBTransaction);
end;
清除数据库后,我仍可以将记录加载到dbgrid中,好像数据库尚未更新。程序重新启动后,我可以看到所有记录都已删除。
答案 0 :(得分:1)
整个function TfrmLogger.db_events_clearall
似乎非常可疑。
SQL_DELETE_ROW
,但是通过回答,这似乎不是返回“结果集”的SELECT请求。因此,很可能它不应由“ .Open”运行,而应由“ .Execute”或“ .ExecSQL”或类似名称运行。 UPD。 SQL_DELETE_ROW = 'DELETE FROM MEVENTS';
被添加,确认了我之前和以后的期望。几乎。常量名称建议您要删除一个行,而查询文本显示您要删除所有行,这是正确的,我想知道吗?..
此外,由于没有“结果集”-.Close
之后没有.Exec....
的内容-但是您可以检查.RowsAffected
,看看DBX中是否有这样的属性,以查看实际计划删除多少行。
此外,不,此功能不删除行,它仅计划将其删除。在处理SQL时,您必须花费时间和精力来学习有关TRANSACTIONS的知识,否则您很快就会被副作用所淹没。
尤其是在这里,您必须提交删除事务。为此,您必须显式创建,启动并绑定到IBQuery
事务,或者找出IBQuery1
和.Commit;
隐式使用的事务。还有.Rollback
的例外情况。
是的,很无聊。您可能希望IBX足够聪明,可以偶尔为您执行提交。但是,如果不通过事务隔离数据更改,您将不可避免地会产生来自各种“竞争条件”的可重现的“副作用”。
示例
FieldDefs.Clear; // frankly, I do not quite recall if IBX has those, but probably it does.
Fields.Clear; // forget the customizations to the fields, and the fields as well
Open; // Make no Exception here
Close;
Halt; // << insert this line
Result := 1;
尝试一下,我敢打赌即使查询是“打开”和“关闭”而没有错误,您的表也不会被清除。
整个With SQL do begin
怪物都可以用单线SQL.Text := SQL_DELETE_ROW;
代替。了解Delphi中的TStrings
类是什么-在Delphi库的很多地方都使用了该类,因此可以节省许多时间来了解此类服务和功能。
您无法忘记Prepare
的一次性查询。在不更改SQL.Text
而是仅更改参数的情况下,对查询进行了准备,然后使用“相同的文本”但使用不同的值重新打开查询。
好的,有时我确实使用(滥用?)显式准备来确保库从服务器获取参数数据类型。但是在您的示例中没有。但是,您的代码不使用参数,也不会使用具有相同的不变SQL.text
的许多打开。因此,它变成一种噪音,使打字时间更长,阅读更困难。
尝试使用ShowMessage(E.ClassName + ^M^J + E.Message)
或仅尝试Application.ShowException(E)
-没有意义使两个停止模式窗口而不是一个停止。
Datamodule1.IBQuery1.close;
-实际上,这是回滚事务的地方,而不仅仅是关闭一直未打开的查询。
现在,使两个(或更多?)SQL请求抛出一个Delphi查询对象的想法本身就值得怀疑。您对查询进行自定义,例如修复DisplayFormat
或设置字段的事件处理程序,那么该查询就值得永久地进行自定义。您甚至可以在设计时设置DisplayFormat
,为什么不这样呢?
在单个TIBQuery
对象上进行骑行没有什么意义-拥有所需的数量即可。到目前为止,您必须普遍且准确地推断出程序中每个函数中的文本都位于IBQuery1
中。
这再次产生了潜在的未来副作用。想象一下,您在某个地方可以做function1; function2;
,后来您决定要交换它们并去做function2; function1;
。你可以做到吗?但是,如果function2
更改IBQuery1.SQL.Text
和function1
取决于先前的文本,该怎么办?那怎么办?
因此,基本上,对查询进行排序。应该存在确实存在于函数调用中的那些查询,然后它们最好具有专用的查询对象,并且不要被其他查询过度使用。而且应该有“一次”查询,这些查询只能在一个函数内部使用,而不能在函数外部使用,例如SQL_DELETE_ROW
-如果谨慎使用,您可能会过度使用这些查询。但是,最好还是重新制作这些函数,使其查询成为局部变量,只有他们自己看不见。
PS。似乎您对IBX库感到困惑,然后建议您看一下此扩展http://www.loginovprojects.ru/download.php?getfilename=uploads/other/ibxfbutils.zip 除其他功能外,它还提供了通用的插入/删除功能,该功能将在内部创建和删除临时查询对象,因此您无需考虑。
交易管理仍然需要牢记和控制。