我熟悉使用ADO(dbGo)的Microsoft SQL服务器世界,我已经为该环境编写了许多应用程序.现在我有一个遗留的Delphi 7应用程序和Firebird 2.5数据库,我必须维护它.
但我发现如果2个客户端应用程序执行此操作:
SQLQuery.SQL.Text := 'Update mytable set field1 = 11 where keyfield = 99'
SQLQuery.Execute;
Run Code Online (Sandbox Code Playgroud)
在几乎完全相同的时间,第二个应用程序立即出现"死锁"错误.在SQL Server中,会有一段等待时间
ADOConnection.Isolationlevel = ilCursorstability;
ADOConnection.CommandTimeout := 5;
Run Code Online (Sandbox Code Playgroud)
在第二个客户端应用程序中引发任何异常之前.异常处理可能涉及在批处理过程中被视为非常不寻常的情况的回滚.这是合理的.5秒是计算机处理时间非常长的时间.
现在,我在Firebird客户端上使用相同方法的尝试毫无结果,因为"死锁"(实际上是使用中的记录)立即发生.
如果无法将数据库引擎配置为等待一些条件来改进(记录锁定要发布),那么现在责任必须由客户端应用程序开发人员负责,他们必须编写疯狂的慢速代码来克服我认为是主要的Firebird失败了.
一旦检测到"死锁",除非断开连接组件,否则不会清除该情况
while rowsupdated = 0 and counter < 5 do
begin
try
rowsupdated := SQLQuery.Execute;
except
SQLConnection.Connected := False;
SQLConnection.Connected := True;
end;
Inc(Counter)
end;
Run Code Online (Sandbox Code Playgroud)
当您在使用Delphi中的DBX时在Firebird中没有任何实质性的锁定容差时,如何构建健壮的多用户表更新客户端?
我试图在大型项目中记录SQL调用,而不对代码进行大量更改.为了开始这个过程,我们决定尝试记录执行的DBX查询.
所以我有:
procedure TRService.GetContactInfo(sessionid: String; msrno: Integer);
var
SQL: String;
qryContact: TSQLQuery;
username: String;
begin
qryContact := TSQLQuery.Create(nil);
qryContact.SQLConnection := TSQLConnection1;
qryContact.SQL.Add('select name, address');
qryContact.SQL.Add('from contact');
qryContact.SQL.Add('where (msrno = :msrno)');
qryContact.ParamByName('msrno').AsInteger := msrno;
{$ifdef LOGSQL}
SQL := qryContact.???
LogSQL(SQL);
// CallNewServer(SQL);
{$else}
qryContact.Open;
{$endif}
end;
Run Code Online (Sandbox Code Playgroud)
结束;
调用LogSQL函数时,我希望它能够记录
'从联系人中选择*(msrno = 12345)'
哪个属性'.???' 我可以使用TSQLQuery来为我提供已经用值替换的参数的SQL字符串吗?理想情况下,我想在此之前执行此操作qryContact.open,因为在将来的版本中,qryContact.open将由对不同服务器的调用替换.
在针对 Android API < 24 的早期版本的 Delphi(10.3 Rio 之前)中,可以创建文件意图,如使用 delphi 使用外部图库打开图像的问题的答案中所示
但是,现在 10.3 以 Android API >= 24 为目标,该代码会产生作为此问题主题的错误。
我努力在Delphi Use android fileprovider to send intent to open and image file with the default android gallery中回答这个问题,但该问题被关闭为重复,即使答案更接近,是在 Android Java 中而不是在 Delphi 中。我的答案如下(经过几个小时的研究)
这在Delphi XE2中对我不起作用.
Var
XMLDoc : IXMLDOCUMENT;
begin
XMLDoc := NewXMLDocument;
XMLDoc.Active := True;
XMLDoc.Version := '1.0';
XMLDoc.Encoding := 'utf-8';
XMLDoc.Options := [doNodeAutoIndent];
Memo1.Text := XMLDoc.XML.Text;
Run Code Online (Sandbox Code Playgroud)
我仍然没有得到encoding="utf-8"?>生成的文档.但如果我说
XMLDoc.Encoding := 'utf-16';
Run Code Online (Sandbox Code Playgroud)
那么我确实得到encoding="utf-16"?>了最终的文档.
有任何想法吗?任何人?
在Delphi FMX XE7,Win32中,我有一个记录类型:
type TSettingsRec = record
SessionTimeOut: Word;
EventString: String[50];
end;
Run Code Online (Sandbox Code Playgroud)
当我将目标更改为Android时,我收到编译错误:
[DCC错误] MainForm.pas(45):E2029';' 预期,但'''发现
我需要定义EventString元素的长度[50],因为TRecord实际上是从数据库(Firebird)读取的,该数据库是由Delphi 7程序使用Bin2Hex写入数据库的(原因只有作者才知道)程序):
var
rec: TSettingsRec;
settings: string;
SetLength(settings, SizeOf(rec)*2);
BinToHex(@rec, @settings[1]), SizeOf(rec));
Run Code Online (Sandbox Code Playgroud)
我使用XE7(win32)有效解码:
var
rec: TSettingsRec;
settings: String;
SetLength(settings, SizeOf(rec) * 2);
System.Classes.HexToBin(Pchar(settings), @rec, SizeOf(rec));
Run Code Online (Sandbox Code Playgroud)
但是,当我为Android编译时,这不起作用.那么如何在Android平台上指定EventString的长度[50]呢?
我创建了一个测试新的FMX项目.添加了TabControl.使用上下文菜单添加3个选项卡.在第3个标签页中添加了一个TEdit.为tabcontrol添加了OnChangeEvent处理程序.编码如下:
procedure TForm1.TabControl1Change(Sender: TObject);
begin
if TabControl1.ActiveTab = TabItem3 then
begin
self.ActiveControl := Edit1;
self.Focused := Edit1;
Edit1.SetFocus;
end;
end;
Run Code Online (Sandbox Code Playgroud)
如您所见,我根据之前的VCL体验尝试了各种组合.输入/光标焦点不会通过代码更改为Edit1.当然,在Win32的运行时,如果我点击edit1,焦点矩形(我正在使用一种样式)现在就像光标一样显示.(正如预期的那样)在Android上.当我自己转移焦点时,VK才出现.
有没有办法以编程方式执行此操作,以便用户可以开始键入?(无需将焦点转移到TEdit本身).
最近我发现了一些奇怪的(对我而言)Delphi代码,我把它分离到一个单独的小项目中.这是我发现的.Unit1编译没有错误.Unit2(我提供用于比较)没有.区别在于Classes的方式used.
unit Unit1;
interface
uses Classes; // difference here
type TThread = class(Classes.TThread)
public
property Terminated;
end;
implementation
end.
Run Code Online (Sandbox Code Playgroud)
Unit2无法编译.产生各种错误.
unit Unit2;
interface
uses System.Classes; // difference here
type TThread = class(Classes.TThread)
public
property Terminated;
end;
implementation
end.
[dcc32 Error] Unit1.pas(7): E2003 Undeclared identifier: 'Classes'
[dcc32 Error] Unit1.pas(7): E2029 ',' or ':' expected but ')' found
[dcc32 Error] Unit1.pas(9): E2147 Property 'Terminated' does not exist in base class
Run Code Online (Sandbox Code Playgroud)
所以我担心的是这个项目正在利用编译器错误来实现它的目标.编译器错误可能会在以后的版本中修复,然后代码将不再起作用.
我正在使用10.3.1(4899).在我项目中表单的最顶部,我有几行看起来像这样:
{$ifdef AA}
{$define BB}
{$endif]
{$define CC}
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我检查定义并采取相应的行动:
procedure TForm1.Button1Click(Sender: TObject);
begin
{$ifdef AA}
ShowMessage('AA');
{$endif}
{$ifdef BB}
ShowMessage('BB');
{$endif}
{$ifdef CC}
ShowMessage('CC');
{$endif}
end;
Run Code Online (Sandbox Code Playgroud)
也许这应该是一个竞争:当我点击按钮时会显示哪条消息?好的,放弃?答案是没有显示消息.行为是预期的,还是一个错误?
随着XE7中非阻塞MessageDlg的出现,似乎现在无法有条件地阻止该应用程序.从我们在Windows中关闭(或在XE5中):
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := False;
FCanClose := False;
FMX.Dialogs.MessageDlg('Exit?'
,
TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
procedure(const AResult: TModalResult)
begin
if AResult = mrYes then
FCanClose := True;
end
);
CanClose := FCanClose;
end;
Run Code Online (Sandbox Code Playgroud)
仅在表单已关闭后才调用MessageDlg(和匿名过程),从而使对象失效.哦,如果你想知道我为什么使用FCanclose,那是因为我在匿名程序中遇到了"无法捕获Canclose"的编译器错误.
现在我尝试的另一种可能性是将MessageDlg放在FormKeyUp事件处理程序中并捕获vkHardwareBack.
procedure TfrmMain.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
Shift: TShiftState);
var
FService: IFMXVirtualKeyboardService;
begin
if Key = vkHardwareBack then
begin
TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyBoardService,
IInterface(FService));
if (FService <> nil) then
begin
if (TVirtualKeyBoardState.Visible in FService.VirtualKeyBoardState) then
else
begin
FMX.Dialogs.MessageDlg('Exit?'
, …Run Code Online (Sandbox Code Playgroud) delphi ×9
android ×3
firemonkey ×3
delphi-xe7 ×2
dbexpress ×1
firebird ×1
interbase ×1
sql ×1
txmldocument ×1