Mi sono imbattuto in questo problema ieri quando ero impegnato a scrivere alcuni test di unità usando SQLLite. Il mio ambiente è Windows 7/Delphi XE.L'utilizzo di un parametro datetime con ADO (ODBC) perde la parte del tempo
L'utilizzo di TADOQuery in combinazione con un parametro TDateTime comporta la perdita della parte relativa all'ora.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ADODb, DateUtils, DB;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var DbConn : TADOConnection;
Qry : TADOQuery;
DT : TDateTime;
begin
DBConn := TADOConnection.Create(nil);
DBConn.ConnectionString := 'Provider=MSDASQL.1;Extended Properties="DRIVER=SQLite3 ODBC Driver;Database=:memory:;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"';
// DBConn.ConnectionString := 'Provider=MSDASQL.1;Persist Security Info=True;User ID=%0:s;Password=%1:s;Extended Properties="DRIVER={MySQL ODBC 5.1 Driver};SERVER=localhost;PORT=3306;DATABASE=test;USER=root;PASSWORD=rrr;OPTION=1048579"';
Qry := TADOQuery.Create(nil);
Qry.Connection := DbConn;
try
DBConn.Connected := True;
Qry.SQL.Text := 'CREATE TABLE test(d datetime)';
Qry.ExecSQL;
Qry.ParamCheck := True;
Qry.SQL.Text := 'INSERT INTO test (d) VALUES (:d)';
//Qry.Parameters.ParseSQL(Qry.SQL.Text, True); // not needed
TryEncodeDateTime(1999, 12, 12, 10, 59, 12, 0, DT);
Qry.Parameters.ParamByName('d').Value := DT;
Qry.Parameters.ParamByName('d').DataType := ftDateTime;
Qry.ExecSQL;
Qry.SQL.Text := 'SELECT d FROM test';
Qry.Open;
ShowMessage(FormatDateTime('MM/DD/YYYY HH:NN:SS', Qry.FieldByName('d').AsDateTime));
finally
FreeAndNil(Qry);
FreeAndNil(DbConn);
end;
end;
La cosa divertente è che quando io commento la linea Qry.Parameters.ParseSQL(Qry.SQL.Text, True);
apparecchio funzionerà regolarmente. Ho bisogno della parte ParseSQL perché sto costruendo un mini-ORM quindi è necessario sapere quali parametri devono essere mappati. Alcune osservazioni:
- fare lo stesso test con MySQL5 presenta lo stesso problema (a prescindere dalla parte ParseSQL).
- Questo codice funziona con SQL Server e il driver OLEDB.
Ho cercato la rete e trovate alcuni link interessanti:
http://tracker.firebirdsql.org/browse/ODBC-27
http://embarcadero.newsgroups.archived.at/public.delphi.database.ado/201107/1107112007.html
http://bugs.mysql.com/bug.php?id=15681
Il primo collegamento suggerisce 'fissare' ADODB.pas, una cosa che faccio non voglio fare. Leggendo l'ultimo collegamento, sembra che ADO esegua il mapping del valore datetime aggiornato.
risposta io non voglio sentire: utilizzare un'altra libreria/componente (come dbExpress, Zeoslib, ...)
Non sono sicuro di quello che sarebbe essere l'approccio più ragionevole per risolvere questo problema.
Come suggerito da Linas e Marjan Venema, posso omettere la parte ParseSQL. Quindi il codice funziona ora con SQLlite SE ometto la riga Qry.Parameters.ParamByName('d').DataType := ftDateTime;
.
Ma MySQL si rifiuta di salvare la parte del tempo. Qui vedo un problema di compatibilità tra ADO e MySQL ODBC?
Avrei impostato il tipo di dati _prima_ impostando il valore, ma non sono sicuro che avrebbe fatto alcuna differenza. Perché la costruzione di un mini ORM richiede ParseSQL? Ho creato alcune librerie di tipo ORM e non ne ho mai avuto bisogno? IIRC Qry.SQL.Prepare dovrebbe anche popolare la raccolta Parameters. –
Ho bisogno di sapere quali parametri ho nella mia query e i valori saranno mappati da un oggetto usando rtti. vuoi dire Qry.Prepared: = true; ? non fa differenza. – whosrdaddy
@whosrdaddy Non è necessario chiamare ParseSQL da solo. Si chiama automaticamente quando SQL.Text cambia (ParamCheck deve essere True). – Linas