Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Configuring History Policy for @OneToMany


We have solved the problem by setting a ThreadLocal<Timestamp> (unique time
for the running transaction) for the entire transaction of updated entities. 
This time is used in combination with the events below to set start- and
end-times correct.
* PreInsertEvent
* PostMergeEvent
* AboutToUpdateEvent
With this solution all entities have the same start- and end-time.
I log a bug as you recommend.


James Sutherland wrote:
> 
> Your customizer should be run twice on startup as you have the customizer
> set for two classes, and each class needs to be customized.
> 
> The start_time may differ slightly for each insert, as the insert may
> occur at different times (more than one millisecond), this should not
> matter however, the relationship between the rows is based on a range of
> time.  It would probably be better to have only a single transaction start
> time used however, please log a bug for this.
> 
> If the merge only changed the Builder but not the name, then only the
> build will be inserted into.  Both versions of the building will have the
> same name as the date range encompasses both.
> 
> If you created a historical session for the point in time that the
> Building was inserted, but before the Name was inserted, then it may not
> have a name if they inserts took more than 1 millisecond, but any point in
> time after the insert of the Name would get both correctly.
> 
> 
> 
> Daniel Rickardsson wrote:
>> 
>> Hi All,
>> 
>> My problem is about to get the history working for the relation
>> OneToMany.
>> 
>> I have set up a simple project with the following entities:
>> * Building
>> * BuildingName
>> 
>> Here is my Building:
>> @Entity
>> @Historical
>> @Customizer(AnnotatedCustomizers.class)
>> public class Building extends AbstractEntity {
>>     ...
>>     ...
>>     @PrivateOwned
>>     @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
>> mappedBy = "building")
>>     private Collection<BuildingName> names = new
>> ArrayList<BuildingName>();
>>     ...
>>     ...
>>     public void addName(final BuildingName buildingName) {
>>         buildingName.setBuilding(this);
>>         this.names.add(buildingName);
>>     }
>> }
>> 
>> Here is my BuildingName:
>> @Entity
>> @Historical
>> @Customizer(AnnotatedCustomizers.class)
>> public class BuildingName extends AbstractEntity {
>>     ...
>>     ...
>>     @ManyToOne
>>     @JoinColumn(nullable = false)
>>     private Building building;
>> }
>> 
>> The AnnotatedCustomizers gets triggered for all annotations in class, and
>> for the @Historical we call:
>> 
>> public class HistorySupport implements
>> AnnotatedDescriptorCustomizer<Historical> {
>>     ...
>>     ...
>> 
>>     @Override
>>     public void customize(final ClassDescriptor descriptor, final
>> Historical annotation) throws Exception {
>>         this.customize(descriptor);
>>     }
>> 
>>     @Override
>>     public void customize(final ClassDescriptor descriptor) throws
>> Exception {
>>         if (descriptor.getTableName().equals("BUILDING")) {
>>             HistoryPolicy policy = new HistoryPolicy();
>>             policy.addStartFieldName("BUILDING.ROW_START");
>>             policy.addEndFieldName("BUILDING.ROW_END");
>> 
>>             String sourceTableName = descriptor.getTableName();
>>             this.logger.debug("descriptor tableName {}",
>> sourceTableName);
>> 
>>             policy.addHistoryTableName("BUILDING", "BUILDING_HIST");
>> 
>>             policy.setShouldHandleWrites(true);
>> 
>>             descriptor.setHistoryPolicy(policy);
>>         } else {
>>             HistoryPolicy policy = new HistoryPolicy();
>>             policy.addStartFieldName("BUILDINGNAME.ROW_START");
>>             policy.addEndFieldName("BUILDINGNAME.ROW_END");
>> 
>>             String sourceTableName = descriptor.getTableName();
>>             this.logger.debug("descriptor tableName {}",
>> sourceTableName);
>> 
>>             policy.addHistoryTableName("BUILDINGNAME",
>> "BUILDINGNAME_HIST");
>> 
>>             policy.setShouldHandleWrites(true);
>> 
>>             descriptor.setHistoryPolicy(policy);
>>         }
>>     }
>> }
>> 
>> When persisting the above code is triggered twice... so there will be one
>> HistoryPolicy for each entity?! This does not feel right.
>> 
>> When testing:
>> * persist of Building and BuildingName => EclipseLink writes to
>> _HIST-tables but the ROW_START differs.
>> * and then doing a merge of Building gives me another row in _HIST-table
>> for Building but not for BuildingName?
>> * and then when I query with a HistoricalSession (DateTime for ROW_START
>> in Building (HIST) when first inserted) I don't receive BuildingName
>> because ROW_START differs?
>> 
>> Here is my HistoricalSession query code:
>> public <T extends AbstractEntity>T queryByHistory(final Class<T> entity,
>> final String uuid, final DateTime time) {
>>         
>>     ReadObjectQuery query = new ReadObjectQuery(entity);
>>    
>> query.setSelectionCriteria(query.getExpressionBuilder().get("objectId").equal(uuid));
>>     Session historicalSession = 
>> this.entityManager.getServerSession().acquireClientSession().acquireHistoricalSession(
>>             new AsOfClause(time.getMillis()));
>>     return (T) historicalSession.executeQuery(query);
>> }
>> 
>> Can anyone see what's wrong?
>> 
>> /Daniel
>> 
> 
> 

-- 
View this message in context: http://old.nabble.com/Configuring-History-Policy-for-%40OneToMany-tp27874092p28030804.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.



Back to the top