views:

61

answers:

2

Environment Mono, PostgreSQL, .Net MVC, Windows

I'm try to show all events that occur in the future.

In order to do that I'm using the following SQL:

NpgsqlCommand command = new NpgsqlCommand("SELECT * FROM dinners WHERE EventDate >= " + DateTime.Now, dinnerConn);

Now, if I compare DateTime.Now and my EventDate timestamp from the DB, I get the following

(EventDate) 12/18/2010 7:00:00 PM - (DateTime.Now) 10/2/2010 7:59:48 PM

They seem pretty easily comparable to me, but whenever I run this query, I get the following:

ERROR: 42601: syntax error at or near "8"

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: Npgsql.NpgsqlException: ERROR: 42601: syntax error at or near "8"

Source Error: 


Line 106:           try
Line 107:           {
Line 108:               NpgsqlDataReader reader = command.ExecuteReader();
Line 109:               while (reader.Read()) 
Line 110:               {

Source File: c:\Documents and Settings\Andrew\My Documents\Visual Studio 2008\Projects\MvcApplication1\MvcApplication1\Models\DBConnect.cs    Line: 108 

Now, I know the application works otherwise because if I ask it to pull all dinners, or all dinners greater than a specific ID, or a specific dinner, everything works fine, it just seems to be trying to compare timestamp to DateTime.Now.

I know this is something simple. What am I doing wrong?

+2  A: 

This syntax should fix your problem:

NpgsqlCommand sql = db.CreateCommand();
sql.CommandType = CommandType.Text;
sql.CommandText = @"SELECT * FROM dinners WHERE EventDate >= @eventdate ;";
sql.Parameters.Add("eventdate", NpgsqlType.Date).Values = DateTime.Now;

You consider to change your query (reference) so both timestamps are almost the same.

Henrik P. Hessel
Thanks, this got me close enough to figure it out.
andrewheins
+2  A: 

You're building a command as a string and not ensuring that the format the DateTime is serialised in is one that will be interpreted correctly by Postgres.

You could use a consistent formatting by calling DateTime.ToString() with an appropriate format string. For extra safety you could add the appropriate SQL to your string to make sure Postgres casts it explicitly to a date when reading the command, rather than depend upon implicit casting.

However, Npgsql already has code to do this that is covered by its NUnit tests on every build. Much better to rely on that:

NpgsqlCommand command = new NpgsqlCommand("SELECT * FROM dinners WHERE EventDate >= :date", dinnerConn);
command.Parameters.Add(":date", DateTime.Now);

A final alternative is not to pass a DateTime from the .NET at all, but to use SELECT * FROM dinners WHERE EventDate >= now(). This way it will go by when the database considers to be the current date. There's a few minor advantages as far as optimisation of the connection goes, but the main reason for this is to maintain consistency between multiple callers into the same database. Having one place where "now" is defined (in this case the database machine) prevents potential issues with different machines being slightly out of synch.

Jon Hanna
+1 for the suggestion to use now() (or alternately, CURRENT_TIMESTAMP). If you pass in DateTime.Now and there's a mismatch of time zones and the app and db field are not both timezone-aware, you'll get unexpected results. The use of now() avoids that issue.
Matthew Wood