In questi giorni mi sono trovato a dover effettuare una query da una pagina ASP.NET ad un database Access (cosa che ormai non facevo da tanto, visto l'amore che ho verso SQL Server). Per rispettare le varie politiche di sicurezza riguardo gli attacchi di sql injection, mi accingo ad utilizzare la classe OleDbParamter per passare i parametri necessari alla mia query.
Nel mio caso avevo un singolo parametro di tipo "data e ora".
Questo il codice che avevo scritto:

OleDbConnection conn = new OleDbConnection(strConn);

using (conn)
{
OleDbCommand cmd = new OleDbCommand();
using (cmd)
{
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM table WHERE campoData > @dataeora";
OleDbParameter param = new OleDbParameter("@dataeora", DateTime.Now);
cmd.Parameters.Add(param);

conn.Open();
OleDbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
//... }
reader.Close();
}
}

Bene... una volta eseguito questo codice, mi vedo stampare a video questa bellissima eccezione:

System.Data.OleDb.OleDbException: Data type mismatch in criteria expression

Dopo un pò di prove, mi sono accorto che Access vuole il parametro (anche se di tipo DateTime) sotto forma di stringa. Quindi mi è bastato aggiungere la chiamata al metodo ToString() e il mio errore è sparito.

OleDbParameter param = new OleDbParameter("@dataeora", DateTime.Now.ToString());

La cosa però non mi piaceva molto.. e googlando un pò, ho trovato una soluzione un pò più pulita. Basta infatti specificare prima della query, il numero e il tipo dei parametri che andranno utilizzati nella query stessa.

OleDbConnection conn = new OleDbConnection(strConn);

using (conn)
{
OleDbCommand cmd = new OleDbCommand();
using (cmd)
{
cmd.Connection = conn;
cmd.CommandText = "PARAMETERS @dataeora datetime; " +
"SELECT * FROM table WHERE campoData > @dataeora";
OleDbParameter param = new OleDbParameter("@dataeora", DateTime.Now);
cmd.Parameters.Add(param);

//... }
}

Buono a sapersi per le prossime volte.. no ?


TAGS: [Access] [Parameter] [ASP.NET]
Commenti(15) - Posted @ 8/30/2008 7:15:46 PM - Categoria: ASP.NET - Permalink - Share on twitter | facebook


COMMENTI
Autore: Peppe - scritto il 9/2/2008 8:56:16 AM
UPDATE

L'errore viene risolto anche specificando il tipo del parametro che viene passato alla query di selezione.

cmd.CommandText = "SELECT * FROM table WHERE campoData > @dataeora";
OleDbParameter param = new OleDbParameter("@dataeora", OleDbType.DBDate);
param.Value = DateTime.Now;
cmd.Parameters.Add(param);

Questa è sicuramente la soluzione consigliata in termini di performance, poichè non viene fatta un'ulteriore query al database da parte del framework per conoscere il tipo relativo al parametro scelto per la nostra selezione.

Autore: Fabio - scritto il 9/3/2008 12:19:15 PM
xchè nn provare così?

cmd.CommandText = "SELECT * FROM table WHERE CampoData > #@dataeora#";

Ho più volte utilizzato # addirittura per fare confronti tra date nella funzione DLookUp nelle tesxtbox dei reports di access

risultato: risparmio codice per definire tipologie di parametri

P.S. lasciate perdere Access ke è ormai è obsoleto :)

Autore: Peppe - scritto il 9/3/2008 12:34:22 PM
Eh no.. non si può !
Così da errore di sintassi.
Il cancelletto serve nel caso in cui si voglia specificare la data in forma testuale all'interno della query. Quindi così:

SELECT * FROM table WHERE CampoData > #03/09/2008 00.00.00#

se viene inserito un parametro all'interno dei cancellati, viene sollevato un'errore di sintassi.

Autore: Marco - scritto il 3/10/2009 11:32:45 AM
Ciao Peppe, ho una query in Access che prende come parametri proprio due date. Utilizzando quello che dici tu,

OleDbParameter param1 = new OleDbParameter("@inizio", OleDbType.DBDate);

OleDbParameter param2 = new OleDbParameter("@fine", OleDbType.DBDate);

Assegno i valori (che provengono da un controllo di tipo datepicker) e aggiungo i parametri.

Se lancio la query da Access, passando i parametri esattamente come provengono da codice (facendo debug e copiando-incollando i valori dalla command window) funziona perfettamente, mentre lanciando la query da codice praticamente ignora i parametri... Mi sai aiutare?

Autore: Marco - scritto il 3/10/2009 11:33:18 AM
Il metodo è il seguente:

public DataTable AutomezziLiberi( int idTipologia, Orario orario )
{
OleDbConnection conn = new OleDbConnection( ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString );

try
{
OleDbCommand cmd = new OleDbCommand( "AutomezzoLibero", conn );
cmd.CommandType = CommandType.StoredProcedure;
OleDbParameter tipologia = new OleDbParameter( "@tipologia", idTipologia );
OleDbParameter inizio = new OleDbParameter( "@inizio", OleDbType.DBDate );
OleDbParameter fine = new OleDbParameter( "@fine", OleDbType.DBDate );
inizio.Value = orario.DataInizio;
fine.Value = orario.DataFine;
cmd.Parameters.Add( tipologia );
cmd.Parameters.Add( inizio );
cmd.Parameters.Add( fine );

conn.Open();
OleDbDataAdapter da = new OleDbDataAdapter( cmd );
DataTable dt = new DataTable();
da.Fill( dt );

return dt;
}
catch ( Exception ex )
{
return null;
}
finally
{
if ( conn.State != ConnectionState.Closed )
conn.Close();
}
}

Autore: Peppe - scritto il 3/11/2009 12:53:08 PM
Ma ti da eccezione oppure no ?
Comunque, dovresti provare ad aggiungere la direzione del parametro:

fine.Direction=ParameterDirection.Input;

con le query, salvate direttamente in access non ho ancora provato..

Autore: Peppe - scritto il 3/11/2009 12:53:37 PM
In ogni caso, leggiti questo:

http://www.aspitalia.com/articoli/db/storedqueries-p-2.aspx

Autore: Marco - scritto il 3/12/2009 2:47:10 PM
Grazie per la risposta. In realtà non dà nessun errore, ma è come se ignorasse le date. Quindi mi dà tutte le righe indipendentemente dai parametri. Vado a leggere quello che mi hai indicato.

Autore: Marco - scritto il 3/12/2009 3:00:38 PM
Ho letto l'articolo, ma purtroppo non mi è stato d'aiuto. Ho messo la direzione dei parametri ma ancora niente. Devo specificare anche il size? E nel caso quanto?

Autore: Peppe - scritto il 3/12/2009 6:13:13 PM
Non, nel caso specifico delle date, non serve specificare l'attributo size.
A questo punto, mi sa che lato C# non stai sbagliando niente.. bisognerebbe vedere la query..
Se metti la stessa query all'interno della proprietà CommandText funziona ?

Autore: Marco - scritto il 3/13/2009 11:05:03 AM
In effetti ho provato anche a mettere la query nel CommandText senza parametri ma inserendo direttamente i valori al suo interno (del tipo #09/03/2009 9.00.00#) ma continua a non funzionare... Sinceramente credo sia un problema di provider a questo punto.

Sto pensando di cambiare il tipo di dato in stringa e mettere le date in formato yyyymmdd, ma così perderei l'ora che invece mi serve.
Maledetto Access!

Autore: Marco - scritto il 3/13/2009 2:10:43 PM
Ti vuoi fare una risata?
Invece di scrivere:

cmd.Parameters.Add( tipologia );
cmd.Parameters.Add( inizio );
cmd.Parameters.Add( fine );

in quest'ordine, ormai arrivato alla frutta e provando le soluzioni più assurde, ho provato a cambiare l'ordine dei parametri come me li chiedeva Access eseguendo la query direttamente.
Quindi ho scritto:

cmd.Parameters.Add( fine );
cmd.Parameters.Add( inizio );
cmd.Parameters.Add( tipologia );

Ha funzionato. Allucinante, non ho altre parole.

Grazie del tuo interessamento, magari puoi integrare il tuo articolo con questa cosa piuttosto strana! Ciao!

Autore: Peppe - scritto il 3/13/2009 3:07:40 PM
Eh si.. purtroppo c'è poco da ridere, perchè Access funziona da sempre così. I parametri non sono nominali, ma seguono l'ordine con cui vengono inseriti all'interno della query.
Era per questo che volevo vedere il tipo di query che stavi scrivendo.. perchè era capitato anche a me (anni fa), di incappare in questo tipo di errore..
meglio così cmq no ? :)

A presto e buon lavoro

Autore: Marco#2 - scritto il 3/26/2009 7:37:20 PM
Ciao a tutti mi sono imbattuto in questo inferno di oleDb. Volevo inserire nel Db access in un campo data generica le informazioni relative a data e ora. Volendo evitare di trasformare in striga Now() e quindi usare una query parametrica ho provato quello che ha suggerito Peppe. Tuttavia OleDbType.DBDate memorizza su db solo la data e non l'ora. Per completezza di informazioni bisogna usare OleDbType.Date

quindi...

....
Dim param As OleDbParameter = New OleDbParameter("@dataUpd", OleDbType.Date)
param.Value = Now
myCommand.Parameters.Add(param)

Autore: Peppe - scritto il 3/28/2009 7:02:34 PM
Grazie Marco per il tuo contributo !

INSERISCI UN COMMENTO

Nome *
Indirizzo e-mail
(non verrà pubblicato)
Commento *