Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » History for a OneToMany relationship not working(History of JPA Entity should include sub-entities attached thru a One-To-Many mapping)
History for a OneToMany relationship not working [message #1226789] Thu, 02 January 2014 18:20 Go to next message
Heidi Hinckley is currently offline Heidi HinckleyFriend
Messages: 1
Registered: December 2013
Junior Member
I am having a terrible time implementing EclipseLink JPA History for OneToMany attributes. The heart of the matter is that when I do an 'as of' query on my entity, the JPA object comes back with the correct snapshot for the 'one' level data, but the list (or 'many') reflects the current records, not the historical. When I look at the raw data in the database, everything appears to be stored as I would expect, so I hope it's just a missed step preventing me from pulling it out as I would like. Here are the details:

The Event entity is built with a OneToMany attribute called 'details'.
Event
public class Event implements Serializable {
    protected Long id;
    private List<Detail> details;
    private EventType eventType;
}

Orm.xml snippet
<entity class="program_x.entities.Event" name="Event">
        <customizer class=" program_x.history.HistoryCustomizer"/>
        <attributes>
            <id name="id">
                <generated-value generator="EVNTSEQ" strategy="SEQUENCE"/>
                <sequence-generator name="EVNTSEQ" sequence-name="EVNT_SEQ" allocation-size="50"/>
            </id>
            <one-to-many name="details" fetch="EAGER" orphan-removal="true" mapped-by="event">
                <order-column/>
                <cascade>
                    <cascade-all/>
                </cascade>
            </one-to-many>
            <basic name="eventType">
                <enumerated>STRING</enumerated>
            </basic>
        </attributes>
</entity>

Detail
public class Detail implements Serializable {
    protected Long id;
    private String detailName;
    protected Event event;
}

Orm.xml snippet
<entity class=" program_x.entities.Detail" name="Detail">
        <customizer class=" program_x.history.HistoryCustomizer"/>
        <attributes>
            <id name="id">
                <generated-value generator="DETSEQ" strategy="SEQUENCE"/>
                <sequence-generator name="DETSEQ" sequence-name="DET_SEQ" allocation-size="50"/>
            </id>
            <basic name=" detailName "/>
            <many-to-one name="event"/>
        </attributes>
</entity>

Currently all the entities use the same generic History Customizer.
History Customizer
        HistoryPolicy policy = new HistoryPolicy();
        policy.addStartFieldName("STARTDATE");
        policy.addEndFieldName("ENDDATE");
        policy.addHistoryTableName(descriptor.getTableName(), descriptor.getTableName() + "_HISTORY");
        policy.setShouldHandleWrites(true);

        descriptor.setHistoryPolicy(policy);

In order to allow EclipseLink to drop-and-create all of our required tables at whim, we also use the Entity notation to generate the history tables. Please note that 1) the Event_History table does not require the 'details' attribute to be defined because these entities are ONLY being used for table generation purposes and the One-To-Many magic means that there is not actually a details field in the Event database table... it just created a JPA relationship; and
2) the Detail_History table saves the event field as Long (the ID) (instead of an Event as the Detail entity does).

Event_History
@Entity
@Cacheable(false)
public class Event_History implements Serializable {

    @Id
    @SequenceGenerator(name = "EVNTHISTSEQ", sequenceName = "EVNT_HIST_SEQ", allocationSize = 50)
    @GeneratedValue(generator = "EVNTHISTSEQ")
    private Long hid;

    private Long id;
    @Temporal(TemporalType.TIMESTAMP)
    private Date startDate;
    @Temporal(TemporalType.TIMESTAMP)
    private Date endDate;

    //Not Needed    private List<Detail> details;
    @Enumerated(EnumType.STRING)
    private EventType eventType;
} 

Detail_History
@Entity
@Cacheable(false)
public class Detail_History implements Serializable {

    @Id
    @SequenceGenerator(name = "DETHISTSEQ", sequenceName = "DET_HIST_SEQ", allocationSize = 50)
    @GeneratedValue(generator = "DETHISTSEQ")
    private Long hid;

    private Long id;
    @Temporal(TemporalType.TIMESTAMP)
    private Date startDate;
    @Temporal(TemporalType.TIMESTAMP)
    private Date endDate;

    private String detailName;
    @Column(name = "EVENT_ID")
    private Long event;
}

Test
  @Test
  public void testSpecificEventAsOfDate() throws InterruptedException {

	//setup to create the test Event/targetRecord
        <blah blah>...

        Date targetDate = new Date();
        Long eventId = targetRecord.getId();
        Detail det = targetRecord.getDetails().get(0);
        Long detId = det.getId();

        //find the current record
        Event expectedEvent = eController.get(eventId);
        debugOutput(expectedEvent, detId, "Current");	//pretty print

        Thread.sleep(10000);

        //edit a record so that it has some history
        det.setDetailName("MODIFIED DESC");	//change the event
        targetRecord.setEventType(EventType.B);	//change one of it's details
        try {
            aeController.edit(targetRecord);	//cascaded save
        } catch (Exception ex) {
            fail(ex.getMessage());
        }

        Event eventBEFORE = eController.findEntityAsOfDate(eventId, targetDate);
        debugOutput(eventBEFORE, detId, "Before");
        assertEquals(expectedEvent, eventBEFORE);	//FAILS!!!!!!!!!!

        //now get the current record one more time
        Event eventAFTER = eController.findEntityAsOfDate(eventId, new Date());
        debugOutput(eventAFTER, detId, "After");
        assertNotNull(eventAFTER);
        assertNotSame(eventBEFORE, eventAFTER);
}

Results
Quote:
//---------------------------------------
Current Type: A
Current Det: Detail 1
//---------------------------------------
Before Type: A
Before Det: MODIFIED DESC <--THIS SHOULD SAY 'Detail 1'
//---------------------------------------
After Type: B
After Det: MODIFIED DESC

I saw a couple postings that mentioned adding an additional 'addHistoryTableName' to the History Customizer so I tried breaking out a customizer for each of my Entities and then trying to list more than one history table in each. Then I get an error and no tables at all are created...
History Customizer
        HistoryPolicy policy = new HistoryPolicy();
        policy.addStartFieldName("STARTDATE");
        policy.addEndFieldName("ENDDATE");
        policy.addHistoryTableName("EVENT", "EVENT_HISTORY"); 
        policy.addHistoryTableName("DETAIL", "DETAIL_HISTORY");
        policy.setShouldHandleWrites(true);

Results
Quote:
java.lang.ArrayIndexOutOfBoundsException: -1

at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:696)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:632)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:568)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:799)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.login(DatabaseSessionImpl.java:756)


This is really a show-stopper to us utilizing this technology on our program so any help you can provide would be greatly appreciated.


[Updated on: Mon, 06 January 2014 13:59]

Report message to a moderator

Re: History for a OneToMany relationship not working [message #1276323 is a reply to message #1226789] Mon, 24 March 2014 11:51 Go to previous message
Guenther Grau is currently offline Guenther GrauFriend
Messages: 1
Registered: March 2014
Junior Member
Hi,

I have the same problem, except that we are using annotation based config. Ideally I'd like to use @OneToMany and @JoinColumn, without the additional @ManyToOne mapping, but

http://www.eclipse.org/forums/index.php/t/457514/

suggests, that this doesn't work at all.

So I changed the mappings according to the suggested posting. Now the foreign keys are written properly to the history tables, but doing a find using the history query hints

query.setHint(QueryHints.AS_OF, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(asOf));
query.setHint(QueryHints.MAINTAIN_CACHE, HintValues.FALSE);

only return historic data only for the attributes of the main entity. When I access other mapped child entities through the methods of the main entity, their attributes only show the current values. This is confirmed by logging the issued SQL statements.

Any ideas how to fix this?

Best regards,

Guenther

Previous Topic:NPE merging @ManyToOne entity
Next Topic:JPA Column Annotations
Goto Forum:
  


Current Time: Fri Nov 28 03:37:40 GMT 2014

Powered by FUDForum. Page generated in 0.01625 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software