I noticed that invoking service method with simple select makes MyDomain.class Date field update in DB (clears time). However enclosing the method with #Transactional(readOnly = true) doesn't update the date value.
Why the value is saved into DB?
Here is the service method
#Transactional(readOnly = true)
Date getDate()
{
Date date = null
date = MyDomain.executeQuery("select min(s.startDate) from MyDomain s where ....)[0]
print "Result: " + date
}
The object will only get updated in the database if it is somehow changed after it brought into the hibernate session (selected) and before the the session is closed (usually at the end of the method). Take a look at your object, and see how it might be modified in some way that you did not intend.
Related
I have an Oracle database column of type date, the date format is dd-MMM-yy, when I try and retrieve an entity from the database using the Entity Framework and a date comparison I get back no records.
I use this method for the query
var calendar = _repository.Single<Calendar>(c => DbFunctions.TruncateTime(c.CALNDR_DATE) == DbFunctions.TruncateTime(calendardate));
I've also tried it in various ways:
var calendar = _repository.Single<Calendar>(c => c.CALNDR_DATE) == calendardate);
I thought this one would work for sure:
var calendar = _repository.Single<Calendar>(c => c.CALNDR_DATE.Year == calendardate.Year && c.CALNDR_DATE.Month == calendardate.Month && c.CALNDR_DATE.Day == calendardate.Day);
No matter what I've tried I cannot get the method to bring back a calendar record even though I have verified there is a record with the date I'm passing. The value in the calendardate variable is formatted as mm/dd/yyyy. If I query the database directly using SQLDeveloper I get back a result when I search with this query select * from table where CALNDR_DATE = '17-DEC-15'
But no result if I search for: select * from braidss.tmmis98 where CALNDR_DATE = '12/17/2015' - This is what I see if I check what is generated by the LINQ
My question is how can I handle this comparison so the dates match? I have tried several different ways but nothing has worked so far.
Lets say, i have a "Book" class with field "availableOn"(as shown below).
class Book {
String availableOn;
}
The fields holds values
"All days" or
String representation of a date. For example "13/06/2012"
How can i get all Books that are available within next two days? The below code would throw an exception ("java.util.Date cannot be cast to java.lang.String")
def books = c.list(){
between('availableOn', new Date(), new Date() + 2)
}
PS : Am working on a legacy DB, and so am not suppose to change the schema :(
I think there are 2 problems which the between statement will have:
availableOn cannot be converted to a Date for comparison when its value is All days
Even when availableOn has a date value in it, it is not converted to a Date for the comparison
I'd try something along the lines of this:
def now = new Date()
def books = Book.findAllByAvailableNotEqual("All days").findAll { book ->
Date.parse('dd/MM/yyyy', book.availableOn) > now && Date.parse('dd/MM/yyyy', book.availableOn) < now+2
}
Clearly, this can be done in a nicer way (adding some methods to the domain class for example), but this should illustrate my idea...
I don't have a criteria based solution, but you can try something like this:
Book.executeQuery(
"select book from Book book where book.availableOn = :availableOn or to_date(book.availableOn, :format) between (:startDate, :endDate) ",
[availableOn:"All days", format: "dd/MM/yyyy", startDate: startDate, endDate:endDate])
The problem with my solution is that this query becomes DB dependent. to_date is an Oracle function. You may want to alter this to fit your database
You can use format on a date to get desired string format of it.
new Date().format('dd/MM/yyyy')
And your criteria would get modified to
def books = c.list(){
def todayDateStr = new Date().format('dd/MM/yyyy')
def twoDaysAfterTodayDateStr = (new Date()+2).format('dd/MM/yyyy')
or{
between('availableOn', todayDateStr, twoDaysAfterTodayDateStr)
eq 'availableOn', 'All Days'
}
}
Test if the str comparison works, otherwise other ways has to be used. Sending from phone, excuse my typos.
UPDATE
The above would fail in peculiar cases when dates are like "01/01/2013" and "07/11/2011".
Alternatively, you can use sqlRestriction but in that case it gets tightly coupled with the underlying database. Something like this can be done if Oracle db is used:
def books = c.list(){
def todayDateStr = new Date().format('dd/MM/yyyy')
def twoDaysAfterTodayDateStr = (new Date()+2).format('dd/MM/yyyy')
or{
sqlRestriction "to_date(available_on, 'DD/MM/YYYY') between to_date(todayDateStr, 'DD/MM/YYYY') and to_date(twoDaysAfterTodayDateStr, 'DD/MM/YYYY')"
eq 'availableOn', 'All Days'
}
}
I have a inetgration test case like this :
void testSomething() {
def cardTable = new CardStorage();
cardTable.cardSecurityCode = "something"
def date = new Date()
System.metaClass.static.currentTimeMillis = {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY,11);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
return date.getTime()
}
assert cardTable.save(flush:true) //this works.
}
The line : cardTable.save(flush:true) is working. It asserts true. But the problem is that the dateCreated field is still the same as (new Date()). I wonder,how this can happen. Because I have coded the currentTimeMillis method as per my req. But still grails doesn't pick it up. But I'm sure that my new currentTimeMillis is working (because making error in it, results in a compilation error).
Where I'm missing? How can I disable the timeStamp feature for testing alone?
Thanks in advance.
Java code in core library in new Date() does not and will never pick up your changes in Groovy metaclass code.
I can recommend using joda-time (make dateCreated a DateTime) and setting current time by its means.
Even better way is not to tie your code to the current time, but to pass the time into your class from outside.
Dont use 'dateCreated', grails will automatically fill it in for you.
Why do I need this:
I am working in a project which allows user to choose date in Nepali Bikram Sambat Date format (which is incompatible with Java and SQL's "DATE"). I did it by modifying org.codehaus.groovy.grails.plugins.web.taglib.FormTagLib class's datePicker tagLibrary. And modifying the scaffolding template list.gsp.
My problem :
When user chooses Nepali date from browser and submits the form, I want to read the [day, month, year] and convert it into Java Date object and save into database. (The date will be converted back to Nepali Bikram Sambat when it will be displayed into view).
I tried to print the params in the controller but all the params are already mapped/wrapped into corresponding objects - along with my Nepali Date. So I get sysout of Java's Date from code below :
println params.date
I am wondering how can I intercept the form submit request and modify the date params into English date. I see one solution - using JavaScript ( and rewrite my conversion code into JavaScript) before form submit to convert the params. And just wanted to confirm is there a easy way - like interceptor/filter etc.
Well, assuming you are using input fields with the standard grails datepicker, you should have in your params map the fields being passed, just with a different name. Write a "println params" in your action receiving the request and look for the names of the fields of the datepicker. It was supposed to bring you something like (name of the datepicker field, say * + _year, for year, * + _month for month and so on).
You can create a CustomEditorRegistrar that changes the format from your date before it's wrapped into objects. Like this:
public class CustomDateEditorRegister implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
String dateFormat = 'dd/MM/yyyy'
registry.registerCustomEditor(Date, new CustomDateEditor(new SimpleDateFormat(dateFormat), true))
}
}
And your Date editor could be something like:
class CustomSimpleDateEditor extends CustomDateEditor {
public CustomSimpleDateEditor(SimpleDateFormat formatter, boolean allowEmpty) {
super(formatter, allowEmpty);
}
public String getAsText() {
Date date = (Date)getValue();
try {
String dateText = new SimpleDateFormat("dd/MM/yyyy").parse(date);
return dateText;
}
catch(Exception e) {
e.printStackTrace();
return "";
}
}
}
Your params.date will be converted before it's passed to objects and saved to the db. Anyway, here's a good link explaining it.
Hope it helps!
I have a database table TableA, which has a column 'theDate' for which the datatype in the database is DATE.
When I save a java.util.Date to 'theDate' through GORM it appears to save just the date value when I look at the data in the table by just executing select * from TableA.
However, when I run a query such as:
select * from TableA where theDate = :myDate
No results are found, but if I run something like;
select * from TableA where theDate <= :myDate
I do get results.
So it's like the Time is relevant.
My question is how do I save a Date and query for a Date ignoring the Time completely and just matching on an exact Date only?
Thanks.
note: I have also tried using sql.Date and util.Calendar but to no success.
clearTime()
You can use clearTime() before saving and before comparing to zero out the time fields:
// zero the time when saving
new MyDomain(theDate: new Date().clearTime()).save()
// zero the target time before comparing
def now = new Date().clearTime()
MyDomain.findAll('SELECT * FROM MyDomain WHERE theDate = :myDate', [myDate: now])
joda-time plugin
An alternative would be to install the joda-time plugin and use the LocalDate type (which only holds date information, no times) instead of Date. For what it's worth, I don't think I've worked on a project with dates without using the Joda plugin. It's completely worth it.
If you have date saved without clearing you could retrieve it using range, as Jordan H. wrote but in more simple way.
def getResults(Date date) {
def from = date.clearTime()
def to = from + 1
def results = MyDomain.findAll("from MyDomain where dateCreated between :start and :stop" ,[start:from,stop:to])
}
Your question may be a duplicate. See Convert datetime in to date. But if anyone has more recent information, that would be great.
If that doesn't help, you can hack it the way I might, with a BETWEEN restriction, e.g.
def today = new Date()
def ymdFmt = new java.text.SimpleDateFormat("yyyy-MM-dd")
def dateYmd = ymdFmt.format(today)
def dateTimeFormat = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
def startDate = dateTimeFormat.parse("${dateYmd} 00:00:00");
def endDate = dateTimeFormat.parse("${dateYmd} 23:59:59");
MyDomain.findAll("from MyDomain where dateCreated between ? and ?", [startDate, endDate])
It's definitely not pretty, but it may get you where you're going.
I figured it out.
I used DateGroovyMethods.clearTime to clear the time value before saving.
You can use the DB type date not datetime , in the filed type