From: <hib...@li...> - 2006-07-28 20:35:21
|
Author: ste...@jb... Date: 2006-07-26 13:10:17 -0400 (Wed, 26 Jul 2006) New Revision: 10170 Added: trunk/Hibernate3/test/org/hibernate/test/join/User.java Modified: trunk/Hibernate3/doc/reference/en/modules/persistent_classes.xml trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java trunk/Hibernate3/test/org/hibernate/test/join/JoinTest.java trunk/Hibernate3/test/org/hibernate/test/join/Person.hbm.xml Log: HHH-1713 : via patch; doc changes regarding tuple package refactoring Modified: trunk/Hibernate3/doc/reference/en/modules/persistent_classes.xml =================================================================== --- trunk/Hibernate3/doc/reference/en/modules/persistent_classes.xml 2006-07-26 17:05:35 UTC (rev 10169) +++ trunk/Hibernate3/doc/reference/en/modules/persistent_classes.xml 2006-07-26 17:10:17 UTC (rev 10170) @@ -457,7 +457,7 @@ </sect1> - <sect1 id="persistent-classes-tuplizers" revision="0"> + <sect1 id="persistent-classes-tuplizers" revision="1"> <title>Tuplizers</title> <para> @@ -469,7 +469,7 @@ for the POJO entity mode, the correpsonding tuplizer knows how create the POJO through its constructor and how to access the POJO properties using the defined property accessors. There are two high-level types of Tuplizers, represented by the - <literal>org.hibernate.tuple.EntityTuplizer</literal> and <literal>org.hibernate.tuple.ComponentTuplizer</literal> + <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and <literal>org.hibernate.tuple.component.ComponentTuplizer</literal> interfaces. <literal>EntityTuplizer</literal>s are responsible for managing the above mentioned contracts in regards to entities, while <literal>ComponentTuplizer</literal>s do the same for components. @@ -504,7 +504,7 @@ public class CustomMapTuplizerImpl - extends org.hibernate.tuple.DynamicMapEntityTuplizer { + extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer { // override the buildInstantiator() method to plug in our custom map... protected final Instantiator buildInstantiator( org.hibernate.mapping.PersistentClass mappingInfo) { Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-07-26 17:05:35 UTC (rev 10169) +++ trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-07-26 17:10:17 UTC (rev 10170) @@ -1961,6 +1961,7 @@ final boolean hasDeferred = rootPersister.hasSequentialSelect(); PreparedStatement sequentialSelect = null; ResultSet sequentialResultSet = null; + boolean sequentialSelectEmpty = false; try { if ( hasDeferred ) { @@ -1970,7 +1971,30 @@ sequentialSelect = session.getBatcher().prepareSelectStatement( sql ); rootPersister.getIdentifierType().nullSafeSet( sequentialSelect, id, 1, session ); sequentialResultSet = sequentialSelect.executeQuery(); - sequentialResultSet.next(); + if ( !sequentialResultSet.next() ) { + // TODO: Deal with the "optional" attribute in the <join> mapping; + // this code assumes that optional defaults to "true" because it + // doesn't actually seem to work in the fetch="join" code + // + // Note that actual proper handling of optional-ality here is actually + // more involved than this patch assumes. Remember that we might have + // multiple <join/> mappings associated with a single entity. Really + // a couple of things need to happen to properly handle optional here: + // 1) First and foremost, when handling multiple <join/>s, we really + // should be using the entity root table as the driving table; + // another option here would be to choose some non-optional joined + // table to use as the driving table. In all likelihood, just using + // the root table is much simplier + // 2) Need to add the FK columns corresponding to each joined table + // to the generated select list; these would then be used when + // iterating the result set to determine whether all non-optional + // data is present + // My initial thoughts on the best way to deal with this would be + // to introduce a new SequentialSelect abstraction that actually gets + // generated in the persisters (ok, SingleTable...) and utilized here. + // It would encapsulated all this required optional-ality checking... + sequentialSelectEmpty = true; + } } } @@ -1988,11 +2012,14 @@ //decide which ResultSet to get the property value from: final boolean propertyIsDeferred = hasDeferred && rootPersister.isSubclassPropertyDeferred( propNames[i], propSubclassNames[i] ); - final ResultSet propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs; - final String[] cols = propertyIsDeferred ? - propertyColumnAliases[i] : suffixedPropertyColumns[i]; - - values[i] = types[i].hydrate( propertyResultSet, cols, session, object ); + if ( propertyIsDeferred && sequentialSelectEmpty ) { + values[i] = null; + } + else { + final ResultSet propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs; + final String[] cols = propertyIsDeferred ? propertyColumnAliases[i] : suffixedPropertyColumns[i]; + values[i] = types[i].hydrate( propertyResultSet, cols, session, object ); + } } else { values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY; Modified: trunk/Hibernate3/test/org/hibernate/test/join/JoinTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/join/JoinTest.java 2006-07-26 17:05:35 UTC (rev 10169) +++ trunk/Hibernate3/test/org/hibernate/test/join/JoinTest.java 2006-07-26 17:10:17 UTC (rev 10170) @@ -90,6 +90,39 @@ s.close(); } + public void testSequentialSelectsOptionalData() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + User jesus = new User(); + jesus.setName("Jesus Olvera y Martinez"); + jesus.setSex('M'); + + s.save(jesus); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from Person").list().size(), 1 ); + assertEquals( s.createQuery("from Person p where p.class is null").list().size(), 0 ); + assertEquals( s.createQuery("from Person p where p.class = User").list().size(), 1 ); + assertTrue(s.createQuery("from User u").list().size()==1); + s.clear(); + + // Remove the optional row from the join table and requery the User obj + s.connection().prepareStatement("delete from t_user").execute(); + s.clear(); + + jesus = (User) s.get( Person.class, new Long( jesus.getId() ) ); + s.clear(); + + // Cleanup the test data + s.delete(jesus); + + assertTrue( s.createQuery("from Person").list().isEmpty() ); + t.commit(); + s.close(); + } + protected String[] getMappings() { return new String[] { "join/Person.hbm.xml" }; Modified: trunk/Hibernate3/test/org/hibernate/test/join/Person.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/join/Person.hbm.xml 2006-07-26 17:05:35 UTC (rev 10169) +++ trunk/Hibernate3/test/org/hibernate/test/join/Person.hbm.xml 2006-07-26 17:10:17 UTC (rev 10170) @@ -23,34 +23,20 @@ --> -<hibernate-mapping - package="org.hibernate.test.join" - default-access="field"> +<hibernate-mapping package="org.hibernate.test.join" default-access="field"> - <class name="Person" - table="person" - lazy="true" - discriminator-value="null"> + <class name="Person" table="person" lazy="true" discriminator-value="null"> - <id name="id" - column="person_id" - unsaved-value="0"> + <id name="id" column="person_id" unsaved-value="0"> <generator class="native"/> </id> - - <discriminator column="person_type" - type="string" - length="1" - not-null="false" - force="true"/> <!--unnecessary, in case we had other unknown discriminator values --> - - <property name="name" - not-null="true" - length="80"/> - <property name="sex" - not-null="true" - update="false"/> - + + <!-- force is unnecessary, in case we had other unknown discriminator values --> + <discriminator column="person_type" type="string" length="1" not-null="false" force="true"/> + + <property name="name" not-null="true" length="80"/> + <property name="sex" not-null="true" update="false"/> + <join table="address"> <key column="address_id"/> <property name="address"/> @@ -61,11 +47,8 @@ <subclass name="Employee" lazy="true" discriminator-value="E"> <join table="employee" fetch="select"> <key column="person_id"/> - <property name="title" - not-null="true" - length="20"/> - <property name="salary" - length="0"/> + <property name="title" not-null="true" length="20"/> + <property name="salary" length="0"/> <many-to-one name="manager"/> </join> </subclass> @@ -78,6 +61,17 @@ </join> </subclass> + <subclass name="User" lazy="true" discriminator-value="U"> + <join table="t_user" fetch="select" optional="true"> + <key column="person_id"/> + <property name="login" column="u_login"/> + </join> + <join table="t_silly" fetch="select" optional="true" > + <key column="person_id"/> + <property name="silly"/> + </join> + </subclass> + </class> Added: trunk/Hibernate3/test/org/hibernate/test/join/User.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/join/User.java 2006-07-26 17:05:35 UTC (rev 10169) +++ trunk/Hibernate3/test/org/hibernate/test/join/User.java 2006-07-26 17:10:17 UTC (rev 10170) @@ -0,0 +1,23 @@ +//$Id$ +package org.hibernate.test.join; + +/** + * @author Mike Dillon + */ +public class User extends Person { + private String login; + private String silly; + + /** + * @return Returns the login. + */ + public String getLogin() { + return login; + } + /** + * @param login The login to set. + */ + public void setLogin(String login) { + this.login = login; + } +} |