用TFDBatchMove复制数据库:如何设置从TIMESTAMP到INTEGER的转换



我的程序应该能够在离线模式下工作,而无需连接到远程MySQL数据库。为此,我想创建一个选项,将特定的表下载到本地SQLite数据库,并在工作完成后将其重新部署回服务器。我尝试将TFDBatchMove组件用于此任务。

该解决方案适用于除一个字段外的所有字段:MySQL TIMESTAMP。当前本地DB使用INTEGER来存储时间戳。当我将数据从SQLite复制到MySQL时,我会得到一个错误。在反向操作中,时间戳已损坏。

我想我需要某种类型的数据映射,但我还没有找到如何设置它。有人能帮忙吗?

错误消息:";项目VRDB.exe引发异常类EVariantError,消息为"无效的变体类型转换"项目VRDB.exe引发异常类EDatabaseError,消息为"字段"TimeStamp"的值无效";。

我的测试代码:

procedure TForm1.ButtonDownloadDBClick(Sender: TObject);
var queryFrom, queryTo: TFDQuery;
FDBatchMove: TFDBatchMove;
begin
queryFrom := TFDQuery.Create(nil);
queryTo := TFDQuery.Create(nil);
FDBatchMove := TFDBatchMove.Create(nil);
with FDBatchMove do begin
// Use "always insert record" mode
Mode := dmAlwaysInsert;
// Erase destination dataset before moving data
Options := [poClearDest];
end;
try
queryFrom.Connection := FDConnection2; //MySQL
queryTo.Connection := FDConnection1; //SQLite
queryFrom.SQL.Clear;
queryFrom.SQL.Add('SELECT * FROM Clients');
queryFrom.Open();
queryFrom.Prepare;
queryFrom.Close;
queryTo.SQL.Clear;
queryTo.SQL.Add('SELECT * FROM Clients');
queryTo.Open();
queryTo.Prepare;
queryTo.Close;
with TFDBatchMoveDataSetReader.Create(FDBatchMove) do begin
DataSet := queryFrom;
Optimise := False;
end;
with TFDBatchMoveDataSetWriter.Create(FDBatchMove) do begin
DataSet := queryTo;
Optimise := False;
end;
FDBatchMove.Execute;
finally
queryFrom.Close;
queryFrom.Destroy;
queryTo.Close;
queryTo.Destroy;
FDBatchMove.Destroy;
end;
end;

看来我已经解决了这个问题。我就是这么做的。我假设TimeStamp字段在MySQL中是TIMESTAMP,在SQLite中是INTEGER,在DateTimeFormat = String

非常感谢布莱恩的想法。

您应该修改queryFrom SQL。对于MySQL->SQLite,这样做:

queryFrom.SQL.Add('SELECT ID,Phone,Name,<...>,UNIX_TIMESTAMP(TimeStamp) FROM Clients');

这将把Date字段类型转换为整数时间代码。

对于SQLite->MySQL,这样做:

queryFrom.SQL.Add('SELECT ID,Phone,Name,<...>,datetime(TimeStamp, "unixepoch") FROM Clients');

重要提示:datetime返回字符串。TFDBatchMove将使用默认的DelphiStrToDateTime进行转换。如果你在应用程序中更改了日期格式,它将失败。因此,您要么想在执行前恢复它,要么手动格式化TimeStamp:

queryFrom.SQL.Add('SELECT ID,Phone,Name,<...>,strftime("%d.%m.%Y %H:%M:%S", TimeStamp, "unixepoch") FROM Clients');

另一个重要的注意事项是:由于某些原因,我无法使用Mappings。如果有人知道如何用函数正确映射列,请回复这篇帖子,我会添加食谱。

我的测试代码中也有一个错误。正如您所看到的,我想保持我的ID值,即Primary Key值,与它们完全一样。如果需要,必须在BatchMove Options:中指定poIdentityInsert

FDBatchMove.Options := [poIdentityInsert, <OtherOptions>];

在其他情况下,您将得到一个错误的Fetch command fetched [0] instead of [1] record.

最新更新