I filed: http://issues.apache.org/jira/browse/OPENJPA-1227
In investigating further I also found that a field from the subclass must also be selected to trigger the error (such that the variable seld in JDBCStoreManager.selectBaseMappings() is set to 1). In the issue I attached a patch which forces a join to the superclass table only in the circumstances in which I am seeing the bug, so hopefully that will help someone track it down and figure out a better fix. On Tue, Aug 4, 2009 at 8:59 AM, David Minor <[email protected]> wrote: > Hi Kevin, > > I'm using 1.2.1. If the DataCache is turned on, then the problem surfaces, > otherwise it does not. Both the QueryCache and QuerySQLCache are turned off. > The problem is exhibited every time the DataCacheStoreManager's load method > is called with a set of fields that includes the to-many field in the > superclass (but no other fields in the superclass). > > The code in selectBaseMapping() doesn't add a join to the superclass table > because there are no other fields requested aside from the to-many field. > But later in eagerToMany.selectEagerJoin(), there is no superclass join > created either (only the join from the superclass table to the to-many > table). From what I can tell from stepping through the code, the Join > created in eagerToMany.selectEagerJoin() wraps the SelectImpl from > selectBaseMapping(), and the final sql join is based on that, so the > superclass join never gets created. > > This entity is being fetched with different fetch groups at various points > in the code, so I am guessing that it is first ending up in the cache > without the to-many field, and then being requested with the to-many field > in a fetch group. > > In testing the change from my first email it appears that it does get > applied too broadly. > > The gist of the class structure is this: > > @Entity > @Table(name = AbstractCategoryImpl.TABLE_NAME) > @Inheritance(strategy = InheritanceType.JOINED) > @DiscriminatorColumn(name = "TYPE", discriminatorType = > DiscriminatorType.STRING, length = 255 ) > public abstract class AbstractCategoryImpl { > > public static final String TABLE_NAME = "TCATEGORY"; > > private Set<Category> children = new TreeSet<Category>(); > private Category parent; > private long uidPk; > > @Id > @Column(name = "UIDPK") > @GeneratedValue(strategy = GenerationType.TABLE, generator = > AbstractCategoryImpl.TABLE_NAME) > @TableGenerator(name = AbstractCategoryImpl.TABLE_NAME, table = > "JPA_GENERATED_KEYS", > pkColumnName = "ID", valueColumnName = "LAST_VALUE", > pkColumnValue AbstractCategoryImpl.TABLE_NAME) > public long getUidPk() { > return this.uidPk; > } > > public void setUidPk(final long uidPk) { > this.uidPk = uidPk; > } > > @OneToMany(targetEntity = AbstractCategoryImpl.class, mappedBy = > "parentInternal", cascade = { CascadeType.ALL }) > public Set<Category> getChildren() { > return this.children; > } > > public void setChildren(final Set<Category> children) { > this.children = children; > } > > > @ManyToOne(targetEntity = AbstractCategoryImpl.class, cascade = { > CascadeType.MERGE, CascadeType.REFRESH }) > @JoinColumn(name = "PARENT_CATEGORY_UID") > @ForeignKey > protected Category getParentInternal() { > return this.parent; > } > > protected void setParentInternal(final Category newParent) { > this.parent = newParent; > } > } > > @Entity > @Table(name = CategoryImpl.TABLE_NAME, uniqueConstraints = > @UniqueConstraint(columnNames = "CODE")) > @PrimaryKeyJoinColumn(name = "UIDPK", referencedColumnName = "UIDPK") > @DiscriminatorValue("masterCategory") > public class CategoryImpl extends AbstractCategoryImpl { > > public static final String TABLE_NAME = "TMASTERCATEGORY"; > } > > And the gist of persistence.xml is this: > > <property name="openjpa.ConnectionFactoryProperties" > value="PrettyPrint=true, PrettyPrintLineLength=120"/> > <property name="openjpa.jdbc.EagerFetchMode" value="parallel"/> > <property name="openjpa.jdbc.SubclassFetchMode" value="parallel"/> > <property name="openjpa.QueryCompilationCache" value="false"/> > <property name="openjpa.DetachState" > value="loaded(DetachedStateField=true)"/> > <property name="openjpa.Multithreaded" value="true"/> > > > <property name="openjpa.DataCache" value="true(CacheSize=1000, > SoftReferenceSize=0)"/> > <property name="openjpa.RemoteCommitProvider" value="sjvm"/> > > <property name="openjpa.QueryCache" value="false"/> > <property name="openjpa.jdbc.QuerySQLCache" value="false"/> > > Hopefully that helps. > > > >> >> -----Original Message----- >> From: Kevin Sutter [mailto:[email protected]] >> Sent: Tuesday, August 04, 2009 6:26 AM >> To: [email protected] >> Subject: Re: SQL generation error >> >> Hi David, >> More questions than answers... Can you provide a concrete example of >> this failure? For example, the Entity and Superclass definitions would >> be helpful. The persistence.xml would also be helpful. So, you are >> indicating that if turn on the openjpa.DataCache property, then the >> problem surfaces? >> But, if you remove this property, then everything works as expected? >> The DataCache property automatically turns on the QueryCache, have your >> tried setting the openjpa.QueryCache to "false" while leaving the >> openjpa.DataCache set to "true"? >> >> Is this particular SQL generated incorrectly all the time? That is, if >> you have the proper settings to reproduce the problem (DataCache, >> whatever), does your application always generate the wrong SQL? Or, is >> it sometimes correct? (The reason I am asking this question is whether >> the QuerySQLCache is affecting this scenario or not. You could quickly >> test this out by setting openjpa.jdbc.QuerySQLCache to "false".) >> >> Oh yeah, and what version of OpenJPA are you using? >> >> The concern with the change you suggested below is that we might be >> generating or re-generating SQL too often with the proposed change. >> But, I haven't studied it in great depth due to the questions I had >> above. If you have made the change below, how does the rest of the >> OpenJPA test bucket fare? Any regressions introduced when you run the >> whole bucket? >> >> Thanks, >> Kevin >> >> On Mon, Aug 3, 2009 at 2:36 PM, David Minor <[email protected]> wrote: >> >> > I've encountered a SQL generation bug where a join to a superclass >> > seems to be missing. The problem only occurs when the datacache is in >> > use, and seems to occur when the superclass is loading a single field >> > which is to-many (I'm using parallel eager select, which may be >> > affecting this as well). The field is a collection of the same type as >> >> > the superclass. >> > >> > I believe the problem is in the select generated by the >> > eagerToMany.selectEagerJoin() call in JDBCStoreManager.select(). >> > However, I've found that in JDBCStoreManager.selectBaseMappings(), if >> > I change the >> > line: >> > >> > if (fms[i] == eagerToMany) >> > continue; >> > >> > to: >> > >> > if (fms[i] == eagerToMany) { >> > seld = 0; >> > continue; >> > } >> > >> > to indicate that the select is required, the problem goes away. >> > However, I don't know the ramifications on other SQL generation. >> > >> > If anyone who is more familiar with the SQL generation code could >> > comment, it would be much appreciated. >> > >> > -- >> > _____________ >> > David Minor >> > >> >> >> >> > > > -- > _____________ > David Minor > -- _____________ David Minor
