How do I specify the timezone when inserting or updating a row with timestamp in Spring JDBC Template? - spring-jdbc

In JDBC API, I can simply set UTC timezone using the following
For inserting or updating
PreparedStatement myPreparedStatement = ...
myPreparedStatement.setTimestamp( 1, myDateTime, Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ));
For querying
ResultSet rs = ...
rs.next();
rs.getTimestamp( 1, Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) )
Using Spring JDBC Template, I will need to use something like this to query.
For querying, I don't have any issues because ResultSet is accessible via RowMapper and use the ResultSet to pass on the Calendar instance in UTC. However, for inserting or updating, I only have the following.
NamedParameterJdbcTemplate namedParameterJdbcTemplate = ....
SqlParameterSource parameters = new MapSqlParameterSource().addValue("current_timestamp", myDateTime )
namedParameterJdbcTemplate.update(sql, parameters);
Question
Is there a way to tell the Spring JDBC template to use my specified TimeZone?
I do not prefer to use the TimeZone.setDefault(..) because that's going to affect our legacy modules.

You can use any method of JdbcTemplate which takes PreparedStatementCreator or PreparedStatementSetter as a parameter and set the field's meta information on those objects.

You do not use time zones when setting or storing a date object. Nor should you. Which is why Date objects have no time zone. A date is just a point on a time line.
The time zone offset is set by the client or consuming application so it can use the correct offset for its location/requirements. If you create an offset in the date value everything that consumes that data down stream will always have to know that date is off and will have to manually account for it. Which grows over time to be a huge pain.

Related

Pre run SQL query to be used by ASP.net application

I have a SQL query which is running on a view and on top has lot of wild card operators, hence taking a lot of time to complete.
The data is consumed by an ASP.net application, is there any way I could pre-run the query once in a day so data is already there when asp.net application needs it and only pass on the parameter to fetch specific records.
Much simplified example would be
select * from table
Run every day and result stored somewhere and when asp.net passes on the parameter only specific records are fetched like
select * from table where field3 = 'something'
Either use SQLAgent (MSSQL) or equivalent to run a scheduled process that stores the result into a Table like this...
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MyTemporaryTable]') AND type in (N'U'))
BEGIN
TRUNCATE TABLE [dbo].[MyTemporaryTable];
INSERT INTO [dbo].[MyTemporaryTable]
SELECT * FROM [vwMyTemporaryTable];
END
ELSE
BEGIN
SELECT *
INTO [MyTemporaryTable]
FROM [vwMyTemporaryTableDataSource];
END
or you could store the result in ASP.Net as an Application/Session variable or even a Property in a class that is stored in Application/Session. The Property approach will load the data the first time it is requested, and use memory thereafter.
private MyObjectType _objMyStoredData;
public MyObjectType MyStoredData
{
get
{
if (_objMyStoredData == null)
{
_objMyStoredData = GetMyData();
}
return _objMyStoredData;
}
}
However, if your source data for this report is only 2,000 rows... I wonder if all this is really necessary. Perhaps increasing the efficiency of the query could solve the problem without delving into pre caching and the downsides that go with it, such as re-using data that could be out of date.
You can use redis. You can run the view once the user logs in. Then fill redis with the view data. Set that object in Session Context of user so that it is accessible on all pages. Then when the user logs out. clean up the redis. By this way user won't go to database everytime for result instead will get the data from redis cache. it's very fast. You can contact me if more help is needed.
you can mark it as answer if you find it helpful.

JPA and SQLite3 - Wrong date

A date field in my entity class is defined as below:
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "LAST_EXECUTED")
private Date lastExecuted = new Date();
However, when it is persisted to a SQLite3 database through JPA, the database value is always '1899-12-30'. Do you have any ideas why?
In the database, the field is defined as DATETIME.
I've tried using both SqliteJDBC and Xerial SQLite JDBC.
Update: After turning on SQL debugging in EclipseLink JPA, and turning off parameter binding, it looks like dates are inserted as following:
insert into run (last_executed) values ('{ts ''2012-02-17 10:34:58.013''}');
which, if inserted, manually in SQLite, gives the date '1899-12-30'.
Of course, any workarounds would be greatly appreciated.
The date looks correct in the insert, so seems to be some kind of SQLite issue. You should normally use parameter binding, it seems SQLite does allow Timestamp to be bound, or ignores the DATE portion. What if you use TemporalType.DATE?
Perhaps try through raw JDBC to see exactly what your JDBC drivers issue are?
For the printed syntax if not using parameter binding, you can customize this by creating your own DatabasePlatform subclass. The syntax you printed is the standard JDBC timestamp syntax.
Can you verify that it is a java.util.Date and not a java.sql.Date?
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "LAST_EXECUTED")
private java.util.Date lastExecuted = new Date();
What does the debug output look like if you turn parameter binding back on?
Use smalldatetime solve the problem~~~ Try it.

Where should I manage the createdBy, modifiedBy, createDate, and modifiedDate?

I want to insert the createdBy, modifiedBy, createDate, modifiedDate columns in every database table for manage user activity.
This is the first time I try to do this. Is there a best practice I could follow? Any design pattern good to manage this?
My first thought is to do this in my business logic layer, and in every business classes' insert and update method, i do something like this:
class.createDate = DateTime.Now;
or
class.modifiedDate= DateTime.Now;
class.modifiedBy = CurrentUser.Id;
or
class.createdBy = CurrentUser.Id;
Or there are much better way?
Bryan
This depends on what types of business objects you are managing, and what the rules are around what the create/modified data is needed for. In most cases, this is a database audit trail, and there is no need for this information in the business logic layer. In that case, this information should live at the database level only. If you are using an ORM, that might mean you keep the data with your objects anyway. If you are using stored procs, then they all need to know how to take a user name to tag the record with. The datetimes can be handled by setting a default value of GetDate() on the column.
Well one thing to consider is what time do you want stamped? Do you want the time of the application server or the time on the database server? I always go for the DB server. So in that case the stored procedure (or SQL statements) should be getting current time.
-Krip
You should manage CreatedDate and ModfiedDate at database label only. Default value of the CreatedDate should be Getdate()/SYSDATE and you don’t need to set this value. For ModifiedDate again set the GETDATE()/SYSDATE on every update.
You only need to pass the ModifiedBy userid from your application to the database, in case of insert set the userid for both the column and in the case of update only update the Modified by userId column.
For createdBy and modifiedBy, I usually set this in my business layer using the username of the current user. For createDate and modifiedDate I do this in the 'after' triggers in the database.

Error - SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM

I've been using this piece of code I've written and it's working in this most unclear manner. I wish to insert a row into the database which includes two columns of DateTime:
myrow.ApprovalDate = DateTime.Now
myrow.ProposedDate = DateTime.Now
And yet, when I update the database I receive this error:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
I've even tried copying an inserted value from the database and hard code it into the object being updated:
// I copied this value from the DB
myrow.ApprovalDate = Convert.ToDateTime("2008-12-24 00:00:00.000");
Still same error, the strange part is that the above trick worked for the first insert to the DB but failed from there on. Any ideas what's going on?
A DateTime in C# is a value type, not a reference type, and therefore cannot be null. It can however be the constant DateTime.MinValue which is outside the range of Sql Servers DATETIME data type.
Value types are guaranteed to always have a (default) value (of zero) without always needing to be explicitly set (in this case DateTime.MinValue).
Conclusion is you probably have an unset DateTime value that you are trying to pass to the database.
DateTime.MinValue = 1/1/0001 12:00:00 AM
DateTime.MaxValue = 23:59:59.9999999, December 31, 9999,
exactly one 100-nanosecond tick
before 00:00:00, January 1, 10000
MSDN: DateTime.MinValue
Regarding Sql Server
datetime
Date and time data from January 1, 1753 through December 31, 9999, to an accuracy of one three-hundredth of a second (equivalent to 3.33 milliseconds or 0.00333 seconds). Values are rounded to increments of .000, .003, or .007 seconds
smalldatetime
Date and time data from January 1, 1900, through June 6, 2079, with accuracy to the minute. smalldatetime values with 29.998 seconds or lower are rounded down to the nearest minute; values with 29.999 seconds or higher are rounded up to the nearest minute.
MSDN: Sql Server DateTime and SmallDateTime
Lastly, if you find yourself passing a C# DateTime as a string to sql, you need to format it as follows to retain maximum precision and to prevent sql server from throwing a similar error.
string sqlTimeAsString = myDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fff");
Update (8 years later)
Consider using the sql DateTime2 datatype which aligns better with the .net DateTime with date range 0001-01-01 through 9999-12-31 and time range 00:00:00 through 23:59:59.9999999
string dateTime2String = myDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffff");
MSDN datetime2 (Transact-SQL)
I find using the following works quite well for SQL min/max dates after many DB related errors:
DateTime rngMin = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
DateTime rngMax = (DateTime)System.Data.SqlTypes.SqlDateTime.MaxValue;
Beware when comparing a .Net DateTime to SqlDateTime.MinValue or MaxValue. For example, the following will throw an exception:
DateTime dte = new DateTime(1000, 1, 1);
if (dte >= SqlDateTime.MinValue)
//do something
The reason is that MinValue returns a SqlDateTime, not a DateTime. So .Net tries to convert dte to a SqlDateTime for comparison and because it's outside the acceptable SqlDateTime range it throws the exception.
One solution to this is to compare your DateTime to SqlDateTime.MinValue.Value.
This error occurs if you are trying to set variable of type DateTime to null. Declare the variable as nullable, i.e. DateTime? . This will solve the problem.
The code you have for the two columns looks ok. Look for any other datetime columns on that mapping class. Also, enable logging on the datacontext to see the query and parameters.
dc.Log = Console.Out;
DateTime is initialized to c#'s 0 - which is 0001-01-01. This is transmitted by linqtosql to the database via sql string literal : '0001-01-01'. Sql cannot parse a T-Sql datetime from this date.
There's a couple ways to deal with this:
Make sure you initialize all date times with a value that SQL can handle (such as Sql's 0 : 1900-01-01 )
Make sure any date times that may occasionally be omitted are nullable datetimes
Sometimes in order to write less code it is used to have SQL server set fields like date, time and ID on insert by setting the default value for fields to GETDATE() or NEWID().
In such cases Auto Generated Value property of those fields in entity classes should be set to true.
This way you do not need to set values in code (preventing energy consumption!!!) and never see that exception.
That usually means a null is being posted to the query instead of your desired value, you might try to run the SQL Profiler to see exactly what is getting passed to SQL Server from linq.
Use extension method
public static object ToSafeDbDateDBnull(this object objectstring)
{
try
{
if ((DateTime)objectstring >= SqlDateTime.MinValue)
{
return objectstring;
}
else
{
return DBNull.Value;
}
}
catch (Exception)
{
return DBNull.Value;
}
}
DateTime objdte = new DateTime(1000, 1, 1);
dte.ToSafeDbDateDBnull();
If you put Datetime nullable like DateTime? in your model it doesn't throw exception.
I solved the problem like this in my case.
Usually this kind of error comes when you do DateTime conversion or parsing. Check the calendar setting in the server where the application is hosted, mainly the time zone and short date format, and ensure it's set to the right time zone for the location. Hope this would resolve the issue.
I am seeing the same thing. The error does not happen on insert of a row but on an update. the table I am referencing has two DateTime columns neither of which are nullable.
I have gotten the scenario down to getting the row and immediately saving it (no data changes). The get works fine but the update fails.
We are using NHibernate 3.3.1.4000
If you are using NHibernate, check that appropriate DateTime properties that are nullable are set to nullable in the mappings.
In my case this error was raised because table date column is not null-able
As below:
Create Table #TempTable(
...
ApprovalDate datatime not null.
...)
To avoid this error just make it null-able
Create Table #TempTable(
...
ApprovalDate datatime null.
...)
Change your db column type to datetime2 and add this to your query/command constructor:
SqlMapper.AddTypeMap(typeof(DateTime), System.Data.DbType.DateTime2);
I had a model with DateTime, but my database-table-column was expecting nullable DateTime.
When inserting my model into the DB, my ORM supplied an empty field which resulted in SQL Server raising an SqlDateTime overflow exception.
The solution was simply to make the model DateTime field nullable so that when the ORM inserts the field and nothing is there, it supplies a DBNull value instead of an empty field.
For context; I ran into this problem while using the Dapper ORM.
DateTime.MinValue and DateTime.MaxValue
DateTime.MinValue = 1/1/0001 12:00:00 AM
DateTime.MaxValue = 23:59:59.9999999, December 31, 9999,
exactly one 100-nanosecond tick
before 00:00:00, January 1, 10000

SQL Server 2005 vs. ASP.net datetime format confusion

I've found a similar question on stack overflow, but it didn't really answer the question I have. I need to make sure that my asp.net application is formatting the date dd/mm/yyyy the same as my SQL Server 2005.
How do I verify the date culture (if that's what it's called) of the server matches how I've programmed my app? Are there specific database settings and OS settings? Is it table-specific? I don't want to transpose my days and months.
thank you
When you get a DateTime out of the database, it should be in a non-cultured format (like the DateTime object, based on the number of ticks since a certain date). It is only when you are converting that value into a string that you need to be concerned with culture. In those cases, you can use yourDateTimeValue.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture) to make sure that the information displays correctly.
I belive that if you use SqlParameters ADO.NET will take care of the rest and you don't have to worry about it. Besides, it's good for defending against SQL Injection attacks too! :)
** Watch out because SQL DateTime columns are non-nullable and their minimum value is 1/1/1753 while .net DateTimes are non-nullable with min values of 1/1/0001. **
If you're pulling data from a real DateTime column, by default it will always be in the same standard format. For saving the data to the column, you might want to specify the SqlDbType.DateTime in your parameter.
i ripped this off of http://bytes.com/forum/thread767920.html :
com.Parameters.Add("#adate", SqlDbType.DateTime).Value = DateTime.Now;
Well, if you keep datetime fields in the DB you shouldn't worry about it.
As long as you keep the dates in app strongly typed (DateTime variables) and send the dates through prepared statements with DBParameter/SqlParameter your DB will take them as is.
If you use strings to hold your dates in code, some casts will ensure you send the right values:
string sqlCmd = #"SELECT *
FROM MyTable
WHERE MyDateField = CONVERT(datetime, '{0}', 101)";
// assuming myDateString is a string with a date in the local format
sqlCmd = string.Format(sqlCmd,
Convert.ToDateTime(myDateString).ToString("yyyyMMdd"));
(the code is ugly, but hopefully it gets the point across)
As others have mentioned, you should be OK as far as storing datetimes culturally. What I would recommend is that you store all of your times as standard UTC time. In SQL Server 2005 and older there is no way to store time zone information, but if everything is stored in universal time, you should be OK because the time can be converted to the local time later on.
SQL Server 2008 does have some datatypes that are aware of time zones, and if you're using .NET 3.5 there are tools to assist with time zone handling/conversions.
Definitely keep times in universal format. This will make a world of a difference if you have to work in multiple time zones.

Resources