Hi,
The use case is exposing following concerns
1. A logically bi-directional relation is modeled as a uni-directional
relation. Ideally, Parent (Address) knows about many Children (Phones) and
each Child (Phone) knows about Parent (Address) too. But in this use case,
Address declares mapping for Phones, but Phone does not.
2. However, it is actually 1.5-directional. Because Phone is half-aware
of Address -- not by object reference to Address but by a long value of
Address' primary key. That the long value is actually the primary key of an
Address is not known to OpenJPA -- it is one of those implicit semantics
that is in the developer's mind.
3. The database column PHONE.ADDR_FK which represents this 'implicit'
bi-directional relation becomes the bone of contention. Address thinks he
should fill the column value with the same value of its primary key column
because Address has explicitly declared a mapping to its children via
@ElementJoinColumn. Phone also thinks that it should populate the column
value because it has declared a @Basic mapping to that column. But nobody
knows (except the developer) that they are referring to the same column.
4. To add to the fun, a database assigns the original value for that
column as primary key of Address. That primary key value after it has been
assigned by the database, has to be copied by *someone* copy to that
PHONE.ADDR_FK column. The standard solution for similar situation is to
write a @PostPersist callback in Parent (Address) that will set the Child's
corresponding inverse reference to Parent.
5. And, of course, the user wants all the Phone to be persistent by
cascade from Address.
All the above factors take a bit of toll on OpenJPA where eventually
ADDR_FK column gets updated 3 times
first as insert by the Address due to its mapping to Children
second by insert by the Child with its original null/empty value
third as update from Child as Address.postPersist callback sets
Phone.addressId
No doubt OpenJPA gets confused with so many changes to the same column
especially when order of these three operations itself is controlled by
openjpa.jdbc.UpdateManager setting. OpenJPA does recognize and can manage
when same value is being set to a column more than once during a
flush/commit session. But as per this case, the values are not the same
either.
Now though this 1.5-directional mapping is not 'ideal' -- it is a pretty
common pattern. So is database assigned primary keys. Given this problem,
here is a suggested solution
1. Introduce a notion of 'implicit Foreign Key'.
So Phone.java will look like
@Basic
@Column(name="ADDR_FK", nullable="true")
@ForeignKey(implicit=true)
private long addressId;
2. That implicit foreign key annotation will tell OpenJPA to be more
lenient when it sees the same column being updated multiple times within a
flush/commit session. Because the foreign key is implicit, it will not
manifest into any database schema artifacts either and purely be used
in-memory by OpenJPA to relax its rules about multiple update to the same
column with different values.
A prototype of the above suggestion has been tested locally, not
committed. I will welcome some comments/suggestions as there is a hint of
heuristics in the proposed suggestion. But given that the 1.5 dimensional
mapping is a pattern I have seen in many cases -- OpenJPA should support it.
Better still, if anyone listening to this channel can point out some
solution with existing features of OpenJPA.
Regards --
--
View this message in context:
http://n2.nabble.com/OpenJPA---two-sided-relation-between-objects-Issue-tp687050p722984.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.