I would like to know how to implement temporal tables in JPA 2 with EclipseLink. By temporal I mean tables who define validity period.
One problem that I\'m facing is t
It seems that you can't do it with JPA since it assumes that the table-name and the whole schema is static.
The best option could be to do it through JDBC (for example using the DAO pattern)
If performance is the issue, unless we're talking about tens of millions of records, I doubt that dynamically creating classes & compiling it & then loading it would be any better.
Another option could be using views (If you must use JPA) may be to somehow abstract the table (map the @Entity(name="myView"), then you'd have to dynamically update/replace the view as in CREATE OR REPLACE VIEW usernameView AS SELECT * FROM prefix_sessionId
for example you could write one view to say:
if (EVENT_TYPE = 'crear_tabla' AND ObjectType = 'tabla ' && ObjectName starts with 'userName')
then CREATE OR REPLACE VIEW userNameView AS SELECT * FROM ObjectName //the generated table.
Not exactly sure what you mean, but EclipseLink has full support for history. You can enable a HistoryPolicy on a ClassDescriptor through a @DescriptorCustomizer.
in DAO Fusion, tracking an entity in both timelines (validity and record interval) is realized by wrapping that entity by BitemporalWrapper
.
The bitemporal reference documentation presents an example with regular Order
entity being wrapped by BitemporalOrder
entity. BitemporalOrder
maps to a separate database table, with columns for validity and record interval, and foreign key reference to Order
(via @ManyToOne
), for each table row.
The documentation also indicates that each bitemporal wrapper (e.g. BitemporalOrder
) represents one item within the bitemporal record chain. Therefore, you need some higher-level entity that contains bitemporal wrapper collection, e.g. Customer
entity which contains @OneToMany Collection<BitemporalOrder> orders
.
So, if you need a "logical child" entity (e.g. Order
or Player
) to be bitemporally tracked, and its "logical parent" entity (e.g. Customer
or Team
) to be bitemporally tracked as well, you need to provide bitemporal wrappers for both. You will have BitemporalPlayer
and BitemporalTeam
. BitemporalTeam
can declare @OneToMany Collection<BitemporalPlayer> players
. But you need some higher-level entity for containing @OneToMany Collection<BitemporalTeam> teams
, as mentioned above. For
example, you could create a Game
entity that contains BitemporalTeam
collection.
However, if you don't need record interval and you just need validity interval (e.g. not bitemporal, but uni-temporal tracking of your entities), your best bet is to roll your own custom implementation.
I am very interested in this topic. I am working for several years now in the development of applications which use these patterns, the idea came in our case from a German diploma thesis.
I didn't know the "DAO Fusion" frameworks, they provide interesting information and links, thanks for providing this information. Especially the pattern page and the aspects page are great!
To your questions: no, I cannot point out other sites, examples or frameworks. I am afraid that you have to use either the DAO Fusion framework or implement this functionality by yourself. You have to distinguish which kind of functionality you really need. To speak in terms of "DAO Fusion" framework: do you need both "valid temporal" and "record temporal"? Record temporal states when the change applied to your database (usually used for auditing issues), valid temporal states when the change occurred in real life or is valid in real life (used by the application) which might differ from record temporal. In most cases one dimension is sufficient and the second dimension is not needed.
Anyway, temporal functionality has impacts on your database. As you stated: "which now their primary keys include the validity period". So how do you model the identity of an entity? I prefer the usage of surrogate keys. In that case this means:
The primary key for the table is the object id. Each entity has one or more (1-n) entries in a table, identified by the object id. Linking between tables is based on the entity id. Since the temporal entries multiply the amount of data, standard relationships don't work. A standard 1-n relationship might become a x*1-y*n relationship.
How do you solve this? The standard approach would be to introduce a mapping table, but this is not a naturally approach. Just for editing one table (eg. an residence change occurs) you would also have to update/insert the mapping table which is strange for every programmer.
The other approach would be not to use a mapping table. In this case you cannot use referential integrity and foreign keys, each table is acting isolated, the linking from one table to the others must be implemented manual and not with JPA functionality.
The functionality of initializing database objects should be within the objects (as in the DAO Fusion framework). I would not put it in a service. If you give it into a DAO or use Active Record Pattern is up to you.
I am aware that my answer doesn't provide you with an "ready to use" framework. You are in a very complicated area, from my experience resources to this usage scenario are very hard to find. Thanks for your question! But anyway I hope that I helped you in your design.
In this answer you will find the reference book "Developing Time-Oriented Database Applications in SQL", see https://stackoverflow.com/a/800516/734687
Update: Example
To extend the example implemented with the assumptions above (2 tables, 1-n):
a query to show all entries in the database (all validity information and record - aka technical - information included):
SELECT * FROM Person p, Residence r
WHERE p.ENTITY_ID = r.FK_ENTITY_ID_PERSON // JOIN
a query to hide the record - aka technical - information. This shows all the validy-Changes of the entities.
SELECT * FROM Person p, Residence r
WHERE p.ENTITY_ID = r.FK_ENTITY_ID_PERSON AND
p.recordTo=[infinity] and r.recordTo=[infinity] // only current technical state
a query to show the actual values.
SELECT * FROM Person p, Residence r
WHERE p.ENTITY_ID = r.FK_ENTITY_ID_PERSON AND
p.recordTo=[infinity] and r.recordTo=[infinity] AND
p.validFrom <= [now] AND p.validTo > [now] AND // only current valid state person
r.validFrom <= [now] AND r.validTo > [now] // only current valid state residence
As you can see I never use the ROW_ID. Replace [now] with a timestamp to go back in time.
Update to reflect your update
I would recommend the following data model:
Introduce a "PlaysInTeam" table:
When you list the players of a team you have to query with the date for which the relationship is valid and has to be in [ValdFrom, ValidTo)
For making team temporal I have two approaches;
Approach 1: Introduce a "Season" table which models a validity for a season
Split the team table. You will have fields which belong to the team and which are not time relevant (name, address, ...) and fields which are time relevant for a season (win, loss, ..). In that case I would use Team and TeamInSeason. PlaysInTeam could link to TeamInSeason instead of Team (has to be considered - I would let it point to Team)
TeamInSeason
Approach 2: Do not model the season explicitly. Split the team table. You will have fields which belong to the team and which are not time relevant (name, address, ...) and fields which are time relevant (win, loss, ..). In that case I would use Team and TeamInterval. TeamInterval would have fields "from" and "to" for the interval. PlaysInTeam could link to TeamInterval instead of Team (I would let it on Team)
TeamInterval
In both approaches: if you do not need a seperate team table for no time relevant field, do not split.