You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@isis.apache.org by Boris Toninski <bo...@orangedot.bg> on 2015/05/07 15:16:15 UTC

What is the proper way to implement calculated property

I have a timestamp property called "end date". I want when the user views/enters it, to work only with the date part, but to be stored in the DB as a timestamp. Here is how I tried to implement this in the entity class:

@javax.jdo.annotations.Persistent(defaultFetchGroup="true")
private DateTime endDate;


@javax.jdo.annotations.Column(name = "end_date", allowsNull = "true")
@Property(hidden = Where.ALL_TABLES)
public DateTime getEndDate() {
    return endDate;
}

public void setEndDate(DateTime endDate) {
    this.endDate = endDate;
}

@MemberOrder(sequence = "5")
@Property(notPersisted = true)
@PropertyLayout(named = "End date")
public LocalDate getLocalEndDate() {
    return convertEndDate(getEndDate()); //converts it to Toronto time zone and cuts the time part
}

public void setLocalEndDate(LocalDate localEndDate) {
    setEndDate(convertEndDate(localEndDate)); //converts it to 23:59:59 in Toronto time zone
}

This way the setting of the date does not works. I debugged it and found that right after setting the value, the framework sets it back to null.

I have one more property - "start date" which is implemented the same way and it works.

Initially I have implemented this without the getter and the setter for the field itself (no getEndDate and setEndDate). And working directly with the field, and it was working, but when I enabled auditing, the auditing for this property didn't work.

Please advise what will be the right way to implement it.

Thanks in advance!

RE: What is the proper way to implement calculated property

Posted by Boris Toninski <bo...@orangedot.bg>.
Thanks Dan,

I will try to reproduce the problem in a new project created from the simpleapp archetype.

-----Original Message-----
From: Dan Haywood [mailto:dan@haywood-associates.co.uk] 
Sent: Monday, May 11, 2015 12:19 PM
To: users
Subject: Re: What is the proper way to implement calculated property

Hi Boris,

sorry you haven't had a reply before now.  Let me make amends.


On 7 May 2015 at 14:16, Boris Toninski <bo...@orangedot.bg> wrote:

> I have a timestamp property called "end date". I want when the user 
> views/enters it, to work only with the date part, but to be stored in 
> the DB as a timestamp. Here is how I tried to implement this in the 
> entity
> class:
>
> @javax.jdo.annotations.Persistent(defaultFetchGroup="true")
> private DateTime endDate;
>
>
> @javax.jdo.annotations.Column(name = "end_date", allowsNull = "true") 
> @Property(hidden = Where.ALL_TABLES) public DateTime getEndDate() {
>     return endDate;
> }
>
> public void setEndDate(DateTime endDate) {
>     this.endDate = endDate;
> }
>
>
above looks ok.  DateTime requires the JDO @Persistent annotation.  Per [1] DFG is true by default so that bit is not required.



> @MemberOrder(sequence = "5")
> @Property(notPersisted = true)
> @PropertyLayout(named = "End date")
> public LocalDate getLocalEndDate() {
>     return convertEndDate(getEndDate()); //converts it to Toronto time 
> zone and cuts the time part }
>
> public void setLocalEndDate(LocalDate localEndDate) {
>     setEndDate(convertEndDate(localEndDate)); //converts it to 
> 23:59:59 in Toronto time zone }
>
>
I think you raised a ticket about our possibly broken timezone handling, so I'll ignore that bit.



> This way the setting of the date does not works. I debugged it and 
> found that right after setting the value, the framework sets it back to null.
>
> I have one more property - "start date" which is implemented the same 
> way and it works.
>
> The code above does look correct to me (assuming that
"convertEndDate(...)" does something sensible).

You said that a "startDate" property works fine, so I find it hard to understand why following the same pattern would break elsewhere.

If you can prepare a test case (use our simpleapp archetype as a starting
point) and upload to github, then I'll take a look.




> Initially I have implemented this without the getter and the setter 
> for the field itself (no getEndDate and setEndDate).


That's fine; DataNucleus will continue to work ok.  Because there is no getter and setter, it will not be part of the Isis metamodel (there needs to be at least a getter for that).



> And working directly with the field, and it was working, but when I 
> enabled auditing, the auditing for this property didn't work.
>
>
Auditing works as follows:
- we rely on DataNucleus to tell us that the object is dirtied (the various IsisTransaction#enlist{Created/Updating/Deleted} methods called from the
FrameworkSynchronizer)
- in terms of which audit records to create, Isis loops through the properties that it knows about (so any fields without a getter will be
ignored)
- also, there is an explicit check [2] to exclude any properties that are marked as not persisted.

To be honest, I can't exactly remember the reason for that check [2], other than probably the rationale that if the underlying data is changed and audited, then there's no need to also audit any derived data.

I don't imagine there would be many negative consequences about making this configurable via isis.properties (though we'd leave the default behaviour as it is).  So if you want to raise a ticket / contribute a pull request, then do go ahead.

Cheers
Dan





> Please advise what will be the right way to implement it.
>
> Thanks in advance!
>



[1] http://www.datanucleus.org/products/datanucleus/jdo/types.html
[2]
https://github.com/apache/isis/blob/3183d013d3d756c098ff96ace23951336e12aad6/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java#L1355

Re: What is the proper way to implement calculated property

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
Hi Boris,

sorry you haven't had a reply before now.  Let me make amends.


On 7 May 2015 at 14:16, Boris Toninski <bo...@orangedot.bg> wrote:

> I have a timestamp property called "end date". I want when the user
> views/enters it, to work only with the date part, but to be stored in the
> DB as a timestamp. Here is how I tried to implement this in the entity
> class:
>
> @javax.jdo.annotations.Persistent(defaultFetchGroup="true")
> private DateTime endDate;
>
>
> @javax.jdo.annotations.Column(name = "end_date", allowsNull = "true")
> @Property(hidden = Where.ALL_TABLES)
> public DateTime getEndDate() {
>     return endDate;
> }
>
> public void setEndDate(DateTime endDate) {
>     this.endDate = endDate;
> }
>
>
above looks ok.  DateTime requires the JDO @Persistent annotation.  Per [1]
DFG is true by default so that bit is not required.



> @MemberOrder(sequence = "5")
> @Property(notPersisted = true)
> @PropertyLayout(named = "End date")
> public LocalDate getLocalEndDate() {
>     return convertEndDate(getEndDate()); //converts it to Toronto time
> zone and cuts the time part
> }
>
> public void setLocalEndDate(LocalDate localEndDate) {
>     setEndDate(convertEndDate(localEndDate)); //converts it to 23:59:59 in
> Toronto time zone
> }
>
>
I think you raised a ticket about our possibly broken timezone handling, so
I'll ignore that bit.



> This way the setting of the date does not works. I debugged it and found
> that right after setting the value, the framework sets it back to null.
>
> I have one more property - "start date" which is implemented the same way
> and it works.
>
> The code above does look correct to me (assuming that
"convertEndDate(...)" does something sensible).

You said that a "startDate" property works fine, so I find it hard to
understand why following the same pattern would break elsewhere.

If you can prepare a test case (use our simpleapp archetype as a starting
point) and upload to github, then I'll take a look.




> Initially I have implemented this without the getter and the setter for
> the field itself (no getEndDate and setEndDate).


That's fine; DataNucleus will continue to work ok.  Because there is no
getter and setter, it will not be part of the Isis metamodel (there needs
to be at least a getter for that).



> And working directly with the field, and it was working, but when I
> enabled auditing, the auditing for this property didn't work.
>
>
Auditing works as follows:
- we rely on DataNucleus to tell us that the object is dirtied (the various
IsisTransaction#enlist{Created/Updating/Deleted} methods called from the
FrameworkSynchronizer)
- in terms of which audit records to create, Isis loops through the
properties that it knows about (so any fields without a getter will be
ignored)
- also, there is an explicit check [2] to exclude any properties that are
marked as not persisted.

To be honest, I can't exactly remember the reason for that check [2], other
than probably the rationale that if the underlying data is changed and
audited, then there's no need to also audit any derived data.

I don't imagine there would be many negative consequences about making this
configurable via isis.properties (though we'd leave the default behaviour
as it is).  So if you want to raise a ticket / contribute a pull request,
then do go ahead.

Cheers
Dan





> Please advise what will be the right way to implement it.
>
> Thanks in advance!
>



[1] http://www.datanucleus.org/products/datanucleus/jdo/types.html
[2]
https://github.com/apache/isis/blob/3183d013d3d756c098ff96ace23951336e12aad6/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java#L1355