Doctrine date in save override / before save - symfony1

I have Doctrine model with a date field "date_of_birth" (symfony form date) which is filled in by the user all works 100% it saves to the db as expected, however in the model save() method I need to retrieve the value of this field before save occurs. My problem is that When trying to get the date value it returns empty string if its a new record and the old value if it is an existing record
public function save(Doctrine_Connection $conn = null)
{
$dob = $this->getDateOfBirth(); // returns empty str if new and old value if existing
$dob = $this->date_of_birth; //also returns empty str
return parent::save($conn);
}
How Can I retrieve the value of this field beore data is saved

In Doctrine 1.2 you can override preSave pseudo-event:
// In your model class
public function preSave($event) {
$dob = $this->getDateOfBirth();
//do whatever you need
parent::preSave($event);
}
In Doctrine 2.1 the function names changed.

Generaly pseudo-events in doctrine uses "new" values, however there is getModified() method and it doing exactly what you need.
$modifiedFields = $this->getModified(true);
if(isset($modifiedFields['date_of_birth'])) { //index is available only after change
echo $modifiedFields['date_of_birth']; //old value
}
more info from doc about getModified()

Related

Attempting to map dates to index in ElasticSearch

I am using ElasticSearch and attempting to create an index with a class that has a dynamic type property in it. This property may have strings or dates in it. When indexing, I have been using the code below:
dynamic instance = MyObject.GetDynamicJson();
var indexResponse = client.Index((object) instance, i=>i
.Index("myIndex")
.Type("MyObject")
);
Here's the code for GetDynamicJson().
MyObject has only Name and Value as properties. (apologies, I've had issues in the past with Elastic choking on json without all the quotes, which I have escaped with \ characters):
String json = "{ \"Name\":\" + Name + "\",\"DateValue\":\"";
try {
var date = DateTime.parse(Value);
json += DateTime.ToString("yyyy/MM/dd HH:mm:ss Z") + "\", \"Value\":\"\"}";
} catch { //If the DateTime parse fails, DateValue is empty and I'll have text in Value
json += "\",\"Value\":\"" + Value + "\"}";
}
return json;
For some reason it doesn't seem to like the string in DateValue and I definitely don't know why it's leaving out that property entirely in the error:
For whatever reason, ElasticSearch is completely dumping the DateValue property, doesn't seem to see the DateValue property at all.
I'm getting the error:
{"name":"CreatedDate","value":"2017-11-07T13:37:11.4340238-06:00"}
[indices:data/write/bulk[s][p]]"}],"type":"class_cast_exception","reason":"org.elasticsearch.index.mapper.TextFieldMapper cannot be cast to org.elasticsearch.index.mapper.DateFieldMapper"},"status":500
Later note: I have changed the index creator method to update the mapping. I added a third field to the Object, so now it has properties: Name, Value, DateValue:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
Now, it is successfully mapping and creating a property each time, but it still seems to drop the property I am sending it in the json. It just sets them all to the default datetime: "dateValue": "0001-01-01T00:00:00". This is strange, because when making the dynamic instance I send to Elastic, I use only the MyObject.GetDynamicJson() method to build it. I no longer get the mapping error, but Elastic still seems oblivious to "dateValue":"some date here" in the object when it is set.
OK, I got rid of the dynamic object type (ultimately I wasn't actually getting data from the json method, I had a typo and Elastic was getting the original object directly - it's a wonder it was still handling it). So I let Elastic do the parse using its mapping. In order to do that, I first updated MyObject to include multiple properties, one for each type the incoming property could be (I am only handling text and dates in this case). For the DateValue property of MyObject, I have this:
public DateTime DateValue {
get
{
try
{
return DateTime.Parse(Value);
} catch
{
return new DateTime();
}
}
set
{
try {
DateValue = value;
} catch
{
DateValue = new DateTime();
}
}
}
Now, if Value is a date, my DateValue field will be set. Otherwise it'll have the default date (a very early date "0001-01-01T00:00:00"). This way, I can later search both for text against that dynamic field, or if a date is set, I can do date and date range queries against it (technically they end up in two different fields, but coming from the same injested data).
Key to this is having the index mapping setup, as you can see in this method from the question:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
In order to recreate the index with the updated MyObject, I did this:
if (client.IndexExists("myIndex").Exists)
{
client.DeleteIndex("myIndex");
CreateRecordsIndex(client); //Goes to the method above
}

Grails querying model containing an enum set

My domain class is
class RoomWantedAd{
Set<MateAgeRange> mateAgeRanges
static hasMany=[mateAgeRanges :MateAgeRange]
}
Her MateAgeRange is :
enum MateAgeRange {
TWENTIES('18-29')
,THIRTIES('30-39')
,FOURTIES("40-49")
,FIFTIES("50-59")
,SIXTIES("60+")
final String value
private MateAgeRange(String value) {
this.value = value
}
String toString() { value }
String getKey() { name() }
static belongsTo=[roomWanted:RoomWanted]
}
My problem is searching. In the search page, a person can select 0 or more values in [18-29, 30-39, 40-49, 50-59, 60+]. In the db, 0 or more values among [18-29, 30-39, 40-49, 50-59, 60+] are stored in field 'mateAgeRanges'.
Let db contains [30-39, 50-59] in 'mateAgeRange' field. Let in the search page, the user selects [18-29, 50-59, 60+]. Then the Ad corresponding to the above list must be returned. This is because at least one value in user's selection is present in the db list. How is it possible. Is it possible using an SQL query or grails GORM query.
you have to use exactly the same <g:select/> tag as you are using for create/update. Thus, you will see human readable values like THIRTIES in browser, but in the background the '30-39' values will be used.

Groovy Dynamic Object - How to properly reset properties?

Based on this question I created a Groovy class that will have dynamic properties.
class MyDynamic {
def propertyMissing( String name, value ) {
this.metaClass."$name" = value
value
}
}
So far all good, now I can set some non-existent property with success
MyDynamic dyna = new MyDynamic()
dyna.someProp = new Date()
My problem begins when I have another instance with the same name of property, but with another type
MyDynamic dyna2 = new MyDynamic()
dyna2.someProp = "0" //GroovyCastException: Cannot cast object '0' with class 'java.lang.String' to class 'java.util.Date'
Actually I need this because I'm creating objects with the result of a query without knowing the table and the column. I get the name of the column with the ResultSetMetaData and add the property to the instance of the dynamic object. Later I will use this object to export all the properties and values. In different tables I have the same column name, but with different types.
So my question is: how can I reset this metaClass when I'm done with the instance to not conflict with other instance?
Why not a Expando, a Map or a simple container:
class Dynamic {
def properties = [:]
void setProperty( String name, value ) {
properties[name] = value
}
def getProperty(String property) { properties[property] }
}
d = new Dynamic()
d.name = "yeah"
assert d.name.class == String
d.name = new Date()
assert d.name.class == Date

Data disappearing from the database?

I am running a grails application and I am receiving the weirdest error I've probably ever encountered. One "field" in a model got data that just disappears for no reason.
I have two Model or a Domain class in my project with the following set up:
class Insertion {
String title
Date insertDate
static hasMany = Dataholder
static constraints = {
title(unique: true)
}
}
class Dataholder {
String product
int somenumber
int somenumber2
int somenumber3
Date startDate
Date endDate
List<String> somedatalist
Insertion insertions
static belongsTo = Insertion
static constraints = {
}
}
The "insertion" class is representing every time a user might input a bunch of dataholders. The dataholder represents all the data for that specific product. Important to know is that the data that disappears is contained in the Dataholder model and the ONLY data that disappears is the somedatalist.
This is the magic which is completely confusing, when I insert the data and saves it. It all goes well:
if (!errors) {
dataholderValidator.each {
it.insertion = insertion
it.save()
}
def results = Dataholder.findAllByInsertion(insertion)
I do some validating and apply data to every Dataholder and then if everything goes well, if(!errors) I add the insertion to each object. After that is done I save each objec, saving the data to the database. You may think it's going wrong here but just wait and be amazed.
After saving I get all the Dataholders from the database (since I want to be sure that the data was saved before printing it out to the user) by using the insertion. This is where the strange part begin, what I get back is the correct data:
results.each {
it.somedatalist.each { it2 ->
if(!weekdays.contains(it2))
weekdays.add(it2)
}
}
Populate an array with all the unique items from the datalist. Then printing it out to the view and voila:
Now, we just wait for the users confirm of all the data in the view and when he or she is clicking on a confirm button the insertion title is sent with post to function which would retrieve the data and to my surprise the somedatalist is null.
This is the functionality that retrieves the data:
def result = Insertion.findByTitle(insertionTitle)
def results = Dataholder.findAllByInsertions(result)
When putting a breaking point after results I can for sure confirm that every Dataholder contains the correct the right data except that somedatalist which is equal to null.
I've tried to get the data above by using the Insertion Title instead of just using the object and it works well. I can't understand why the data is populated in the database in one second and how something can just disappear?
Test:
void testSaveDataholder() {
Insertions insertion = new Insertion(title: 'adadad', insertDate: new Date())
insertion.save()
assert Insertion.all.size() == 1
Dataholder ed = new Dataholder(product: 'abc123', somenumber: 123, somenumber2: 13, startDate: new Date(), endDate: new Date(), somedatalist: ['TI'], insertions: insertion)
ed.save()
assert Dataholder.all.size() == 1
assert Dataholder.all.first().somedatalist.size() == 1
assert Dataholder.all.first().insertions.title == 'adadad'
assert Insertion.findAllByTitle('adadad').size() == 1
assert Dataholder.findAllByInsertions(Insertion.all.first()).size() == 1
}
This test all returns true, I am using Grails 2.1.
EDIT: I am using the in-memory database with "update" as configuration. So I can't really view the data. But it should be there.
Please help me with your sage advice and better wisdom.
It just has come to my mind. Persisting a collection of objects into single column breaks the 1st normal form, so it is not the correct way to do it. I have immediately googled an issue in JIRA:
http://jira.grails.org/browse/GRAILS-1023
The correct way is to create a new domain class with single String attibute and use standard one-to-many relation.

How to order by time and time only in C#?

I have this recorded in SQL Server:
1- startTime (datetime): 5/2/2009 08:30 (brazilian time format: d/m/y)
2- startTime (datetime): 4/2/2009 14:30 (brazilian time format: d/m/y)
My application just records time... the date it's SQL that generates by itself be getting the date of today.
When I ask VS 2008 to order this datetime fields, it returns me that code #2 is before #1, because 4/2/2009 comes before 5/2/2009.
But, actually I want it to order by time only and ignore the date.
Is it possible??
Thanks!!
André
from d in dates
orderby d.TimeOfDay
select d;
or
dates.OrderBy(d => d.TimeOfDay);
Note: This will work as long as this is plain LINQ and not LINQ-to-SQL. If you're using LINQ-to-SQL to query your database, you'll need something that will translate to SQL.
You might also try fixing your app so it always saves the same base date with the time (like '01/01/1900' or whatever) and then you do not have to do all these slow and inefficient date stripping operations every time you need to do a query.
Or as Joel said, truncate or strip off the date portion before you do the insert or update.
Well, you can't really store a datetime without a date, but you could just store the total seconds as an double (using #florian's method).
You'd have to add a second method to convert this back to a date in your object, if you still need a date, such as:
public class BusinessObjectWithDate
{
private string _someOtherDbField = "";
private double _timeInMS = 0; // save this to the database
// sort by this? in sql or in code. You don't really need this
// property, since TimeWithDate actually saves the _timeInMS field
public double TimeInMS {
get { return _timeInMS; }
}
public DateTime TimeWithDate { // sort by this too, if you want
get { return (new DateTime(1900,1,1).AddMilliseconds(_timeInMS)); }
set { _timeInMS = value.TimeOfDay.TotalMilliseconds; }
}
}
var f = new BusinessObjectWithDate();
MessageBox.Show( f.TimeWithDate.ToString() ); // 1/1/1900 12:00:00 AM
f.TimeWithDate = DateTime.Now;
MessageBox.Show( f.TimeWithDate.ToString() ); // 1/1/1900 1:14:57 PM
You could also just store the real date time, but always overwrite with 1/1/1900 when the value gets set. This would also work in sql
public class BusinessObjectWithDate
{
private DateTime _msStoredInDate;
public DateTime TimeWithDate
{
get { return _msStoredInDate; }
set {
var ms = value.TimeOfDay.TotalMilliseconds;
_msStoredInDate = (new DateTime(1900, 1, 1).AddMilliseconds(ms));
}
}
}
Try this in your sql:
ORDER BY startTime - CAST(FLOOR(CAST(startTime AS Float)) AS DateTime)

Resources