views:

326

answers:

2

I think the preamble of my use case cluttered my actual point, so I am restating more succinctly: Why can't @Version take a generator and allow me to assign a sequence to it like I can do for @Id; something like this

@Entity
@javax.persistence.SequenceGenerator(
    name="SEQ_STORE",
    sequenceName="my_sequence"
)
public class Store implements Serializable {
    private Long version;

    @Version @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
    public Long getVersion() { return version; }
}

But you can't do this in JPA or Hibernate. Hibernate implements @Version as a simple incremented value 0,1,2...(or timestamp). My point here is I see this as a simple and acceptable use case. Does anyone know why this is not possible to implement in the JPA spec or by Hibernate extension?

EDIT: In my use case was peculiar in that I am using a temporal star schema where Hibernate interfaces via views and triggers do the actual save/update/delete in the fact/dimension tables. The dimension tables act like "log" tables so a snapshot may look like this from table_name:

ID    ENTRY_VALUE    TIME_START       TIME_COMPLETE    PARENT_IS
1     22             10/23/2003 1:38  10/23/2003 1:56  -1
1     23             10/23/2003 1:56  10/23/2003 2:00  22
1     24             10/23/2003 2:00  10/23/2003 2:04  24

What Hibernate would see is a view based on this sql

create view domain_object as select ... from table_name t inner join fact_table f on f.id = t.id where t.time_complete is null

So the 3 rows above represent the lifecycle of a domain object with ID 1. It was created in entry_value 22, updated in 23 and deleted in 24. If I used entry_value as @Version then when i add another domain object say with ID 2 then version numbers start over like this

ID    ENTRY_VALUE    TIME_START       TIME_COMPLETE    PARENT_IS
1     0             10/23/2003 1:38  10/23/2003 1:56    -1
1     1             10/23/2003 1:56  10/23/2003 2:00    22
1     2             10/23/2003 2:00  10/23/2003 2:04    24
2     0             10/23/2003 2:40  null               24

PARENT_IS is invalid in this case, we need to create another column to accommodate the PARENT_IS relation.

So my ultimate point is when Hibernate does an update it goes like this

update table_name set column_name = 10, version_col_name = 2 where column_name = 3 and version_col_name = 1

Checking the version and then updating are 2 semantically diff operations, for optimistic locking all the query cares about is finding version_col_name = 1, if that doesn't exist we get an OptimisticLockException. Updating the version_col_name by incrementing it by 1 is totally secondary to the optimistic locking act and becomes relevant to to the succeeding update. So in a case like mine I would have liked to implement @Version with a sequence as my use case does not keep updating a single row continuously as is the norm.

A: 

I don't know why you see this as a simple and acceptable use case. A version number is incremented each time an object is updated and is used to avoid concurrent modifications. Why would a sequence be better for this? What is the problem with using 0 as starting value? Why would you need a sequence number (the next value) instead of 0 when creating a new instance? What is the point?

Pascal Thivent
A: 

I'm still not 100% clear on what you're trying to do, so please do comment if what I'm suggesting does not address what you meant.

Hibernate does allow for version to be sequence-based, albeit it's not very straightforward:

You need to mark your "version" property as generated, which you can do via Hibernate Annotation extensions and you're free to generate it in your database via whatever means necessary, including taking its value from a sequence.

That said, your use case, while definitely acceptable (because it exists) is neither simple nor common. I'm not sure why you even need optimistic locking as it seems you're trying to maintain entire entity change history and thus presumably doing inserts only (though perhaps I misunderstood your explanation).

ChssPly76
Yeah I guess my use case is really not straightforward, it would require explanation of this star-schema based temporal db. But the issue is resolved with adding a dedicated column to use for @Version. But the jist of my question was just to get some insight on why @Version can't take an optional generator like you can give @Id a generator. But thanks for attempting an answer, to be fair it was a convoluted question to begin with lol :)
non sequitor
Something like this would work is what you're saying@Version@Column(insertable=false,updatable=false)@Generated(GenerationTime.ALWAYS)@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "labelSeq") @SequenceGenerator(name = "labelSeq", sequenceName = "label_id_seq", allocationSize=1, initialValue=1)private Long labelVersion;
non sequitor
What would work is annotation your column as `@Version @Generated(GenerationTime.ALWAYS)`. The actual generation has to be implemented in the database (via trigger / sequence, for example) - `@GeneratedValue` annotation will not work for version. Basically, Hibernate lets you say that version is generated (and will re-read the generated value on insert / update) but it won't generate it for you.
ChssPly76