Home » Eclipse Projects » EclipseLink » Inherited OneToOne relationship not hydrated properly(Inherited OneToOne relationship in EclipseLink 1.0.1 not hydrated properly)
Inherited OneToOne relationship not hydrated properly [message #541625] |
Mon, 21 June 2010 20:10 |
Doug Gschwind Messages: 18 Registered: July 2009 |
Junior Member |
|
|
Hello,
We are using EclipseLink version 1.0.1 and have a One to One relationship that is being written corrrectly to the database, but when instances of the JPA mapped class are later hydrated into Java objects from the database, the One to One relationship is not hydrated correctly and the reference typed instance variable unexpectedly has a value of null. This is the problem.
We have an abstract superclass Sup that has several concrete subclasses, one of which is called Sub (names changed to protect the innocent). Sup, and thus Sub, has two JPA mapped
instance variables lineString and lineStringClob of type String and ClobHolder respectively. lineString is mapped to a column of type VARCHAR2(4000), whereas lineStringClob is mapped to
a column of type RAW(16) as we use that data type to persist relationships. If the line string data is 4000 characters or less, the data is housed in the LINESTRING VARCHAR2(4000) column, otherwise the data of 4001 characters or more is housed in the CLOBHOLDER table and we store the foreign key to that row in the LINESTRINGCLOBID RAW(16) column. Thus, for each row in the source table, LINESTRING or LINESTRINGCLOBID will be null, but not both. One of the two
pieces of information is required to be present in each row of SUP or SUB.
Sup is JPA mapped to the SUP table and Sub is JPA mapped to the SUB table. Those table definitions can be summarized as follows :
SUP SUB
--- ---
SUPID PK RAW(16) NOT NULL SUBID PK RAW(16) NOT NULL
LINESTRING VARCHAR2(4000) LINESTRING VARCHAR2(4000)
LINESTRINGCLOBID RAW(16) LINSTRINGCLOBID RAW(16)
... SUPFK FK RAW(16) NOT NULL
...
The relevant JPA mapped portions of the Sup class is shown below :
@MappedSuperclass
@Customizer(SupDescriptorCustomizer.class)
public abstract class Sup extends AbstractSup {
/**
* Long display -- used if string length < 4001
*/
@Column(name="LINESTRING")
private String lineString;
/**
* Long display -- if string length > 4000
*/
@OneToOne(fetch=LAZY, cascade={ALL})
@JoinColumn(name="lineStringClobId")
@PrivateOwned
private ClobHolder lineStringClob;
...
}
The relevant JPA mapped portions of the Sub class is shown below :
@Entity
@Table(name="SUB")
@Customizer(GeneralDescriptorCustomizer.class)
@AttributeOverride(name="id", column=@Column(name="SUBID"))
public class Sub extends Sup {
...
}
When an instance of the Sup class is read, its line string data should come from the LINESTRING or LINESTRINGCLOBID columns in the SUP table. When an instance of the Sub
class is read however, its line string data should come from the LINESTRING or LINESTRINGCLOBID columns in the SUB table. What we are seeing though is that upon a Sub instance being hydrated where the value in SUB.LINESTRINGCLOBID column is non-null, the ClobHolder in the Sub instance is unexpectedly null.
We have also tried changing the attribute overrides in Sub to look like :
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name="SUBID")),
@AttributeOverride(name="lineStringClob", column=@Column(name="LINESTRINGCLOBID"))
})
or
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name="SUBID")),
@AttributeOverride(name="lineStringClob", column=@Column(name="SUB.LINESTRINGCLOBID"))
})
to no avail. We are seeing that instances of other non-Sub Sup subclasses are being hydrated correctly in this regard. This thus feels like an EclipseLink 1.0.1 bug, but I cannot find any similar complaints in the EclipseLink forum.
Any ideas on what to provide differently in terms of JPA annotations, or other suggestions that might yield properly hydrated instances of Sub, other than simply making another trip
to the database when both the String and ClobHolder instance variables are null in a given Sub instance?
Thank you,
Doug Gschwind
|
|
| | |
Re: Inherited OneToOne relationship not hydrated properly [message #542116 is a reply to message #541779] |
Wed, 23 June 2010 22:17 |
Doug Gschwind Messages: 18 Registered: July 2009 |
Junior Member |
|
|
Hi James,
Hopefully this gives you more of the information you need to be able to help diagnose the issue. Feel free to ask for other information if you need it.
Q: SQL statement for the insert of the Sub instance
A: INSERT IGNORE INTO CLOBHOLDER (CLOBID, CLOBVALUE, OWNERTYPE) VALUES (?, ?, ?)
bind => [[B@cdb963, String in excess of 4000 characters goes here, SVC]
INSERT IGNORE INTO SUB (SUBID, LINESTRING, CLINICALDTM, SUPID, ENTRYDTM, lineStringClobId) VALUES (?, ?, ?, ?, ?)
bind => [[B@1400d67, null, oracle.sql.DATE@2feaf6, [B@16dbf20, oracle.sql.DATE@104ee97, [B@cc15ac]
Please keep in mind that there are more like 20 columns specified in the SUB table, but I have culled
those that are not relevant to the issue.
Q: SQL statement for the select of the Sub instances
A: SELECT s.* FROM Sub s WHERE s.supId=? OR s.supId=? OR s.supId=? OR ... order by s.entryDtm desc
bind => [[B@1922b38, [B@153956b, ..., [B@e0719]
which is followed by many statements of the form:
SELECT CLOBID, CLOBVALUE, OWNERTYPE FROM CLOBHOLDER WHERE (CLOBID = ?)
I should note that not only is Sub a Sup subclass, but a Sup instance can have many
Sub instances. So the select statement you see above is attempting to hydrate many
one to many relationships with one query. The number of supIds provided is much more than the
three I depict here. More like on the order of 100 or so.
Q: Include code for customizers
A: Can you share an email address with me where I can send you these files privately?
Q: If the cache is cleared or disabled, and create a new EntityManager, is the Sub's reference still null?
A: I believe the problem only occurs when the cache is cold and we have to make a trip to the database to
hydrate a Sub instance. What have seen is that if we use getDelegate() against an EntityManager
instance to obtain a reference to an EclipseLink Session, and then call refreshObject() with our Sub
instance as an argument to refreshObject(), the problem remains. However, if we use an EclipseLink classic
ReadObjectQuery, and instruct the query to not use cache, the Sub instance returned from that call is in
fact properly populated, where it was not prior. This is not a direct answer to your question I believe,
but very close.
Q: How are you verifying that the reference value is null?
A: By stepping through the code in the debugger (Eclipse IDE 3.5.2), and seeing that after the
ClobHolder reference is requested, its returned value is unexpectedly null.
Thanks,
Doug
|
|
| |
Re: Inherited OneToOne relationship not hydrated properly [message #542433 is a reply to message #542362] |
Thu, 24 June 2010 19:43 |
Chris Delahunt Messages: 1389 Registered: July 2009 |
Senior Member |
|
|
Hello,
The problem is due to case sensitivity. I'm not sure which database you are using, but because you are using Native SQL for your query, EclipseLink must look up the columnames in the results to find the correct values. It uses the strings defined in the mappings, so if the database you are using returns columnames in uppercase (Oracle and others do), it will not match the "lineStringClobId" defined in the @JoinColumn(name="lineStringClobId").
This is common issue with native SQL queries, and is somewhat solved in bug
https://bugs.eclipse.org/bugs/show_bug.cgi?id=299926
Solutions are to change the columnames to match the case used in the database (defaults are always uppercase, so you will probably want to be consistent anyway), or use a 2.1 EclipseLink version with the fix and set the eclipselink.jpa.uppercase-column-names property to true.
Best Regards,
Chris
|
|
| |
Goto Forum:
Current Time: Fri Apr 19 18:12:33 GMT 2024
Powered by FUDForum. Page generated in 0.05711 seconds
|