Author: epbernard Date: 2006-04-28 11:16:41 -0400 (Fri, 28 Apr 2006) New Revision: 9830 Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/Fetch.java trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/FetchMode.java trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollection.java trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollectionOption.java trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOne.java trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOneOption.java Modified: trunk/HibernateExt/metadata/doc/reference/en/modules/entity.xml trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationBinder.java trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/FetchingTest.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Person.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Stay.java Log: ANN-224 @Fetch(FetchMode) @LazyToOne(LazyToOneOption) @LazyCollection(LazyCollectionOption) Modified: trunk/HibernateExt/metadata/doc/reference/en/modules/entity.xml =================================================================== --- trunk/HibernateExt/metadata/doc/reference/en/modules/entity.xml 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/doc/reference/en/modules/entity.xml 2006-04-28 15:16:41 UTC (rev 9830) @@ -2556,6 +2556,106 @@ <para>In this case Hibernate generates a cascade delete constraint at the database level.</para> + + <sect3> + <title>Lazy options and fetching modes</title> + + <para>EJB3 comes with the <literal>fetch</literal> option to define + lazy loading and fetching modes, however Hibernate has a much more + option set in this area. To fine tune the lazy loading and fetching + strategies, some additional annotations have been introduced: </para> + + <itemizedlist> + <listitem> + <para><literal>@LazyToOne</literal>: defines the lazyness option + on <literal>@ManyToOne</literal> and <literal>@OneToOne</literal> + associations. <literal>LazyToOneOption</literal> can be + <literal>PROXY</literal> (ie use a proxy based lazy loading), + <literal>NO_PROXY</literal> (use a bytecode enhancement based lazy + loading - note that build time bytecode processing is necessary) + and <literal>FALSE</literal> (association not lazy)</para> + </listitem> + + <listitem> + <para><literal>@LazyCollection</literal>: defines the lazyness + option on <literal>@ManyTo</literal>Many and + <literal>@OneToMany</literal> associations. LazyCollectionOption + can be <literal>TRUE</literal> (the collection is lazy and will be + loaded when its state is accessed), <literal>EXTRA</literal> (the + collection is lazy and all operations will try to avoid the + collection loading, this is especially useful for huge collections + when loading all the elements is not necessary) and FALSE + (association not lazy)</para> + </listitem> + + <listitem> + <para> <literal>@Fetch</literal>: defines the fetching strategy + used to load the association. <literal>FetchMode</literal> can be + <literal>SELECT</literal> (a select is triggered when the + association needs to be loaded), <literal>SUBSELECT</literal> + (only available for collections, use a subselect strategy - please + refers to the Hibernate Reference Documentation for more + information) or <literal>JOIN</literal> (use a SQL JOIN to load + the association while loading the owner entity). + <literal>JOIN</literal> overrides any lazy attribute (an + association loaded through a <literal>JOIN</literal> strategy + cannot be lazy).</para> + </listitem> + </itemizedlist> + + <para>The Hibernate annotations overrides the EJB3 fetching + options.</para> + + <table> + <title>Lazy and fetch options equivalent</title> + + <tgroup cols="3"> + <thead> + <row> + <entry>Annotations</entry> + + <entry>Lazy</entry> + + <entry>Fetch</entry> + </row> + </thead> + + <tbody> + <row> + <entry>@[One|Many]ToOne](fetch=FetchType.LAZY)</entry> + + <entry>@LazyToOne(PROXY)</entry> + + <entry>@Fetch(SELECT)</entry> + </row> + + <row> + <entry>@[One|Many]ToOne](fetch=FetchType.EAGER)</entry> + + <entry>@LazyToOne(FALSE)</entry> + + <entry>@Fetch(JOIN)</entry> + </row> + + <row> + <entry>@ManyTo[One|Many](fetch=FetchType.LAZY)</entry> + + <entry>@LazyCollection(TRUE)</entry> + + <entry>@Fetch(SELECT)</entry> + </row> + + <row> + <entry>@ManyTo[One|Many](fetch=FetchType.EAGER)</entry> + + <entry>@LazyCollection(FALSE)</entry> + + <entry>@Fetch(JOIN)</entry> + </row> + </tbody> + </tgroup> + </table> + </sect3> </sect2> <sect2 id="entity-hibspec-collection" revision="2"> Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/Fetch.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/Fetch.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/Fetch.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,18 @@ +//$Id: $ +package org.hibernate.annotations; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Define the fetching strategy used for the given association + * + * @author Emmanuel Bernard + */ +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Fetch { + FetchMode value(); +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/FetchMode.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/FetchMode.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/FetchMode.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,22 @@ +//$Id: $ +package org.hibernate.annotations; + +/** + * Fetch options on associations + * + * @author Emmanuel Bernard + */ +public enum FetchMode { + /** + * use a select for each individual entity, collection, or join load + */ + SELECT, + /** + * use an outer join to load the related entities, collections or joins + */ + JOIN, + /** + * use a subselect query to load the additional collections + */ + SUBSELECT +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollection.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollection.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollection.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,18 @@ +//$Id: $ +package org.hibernate.annotations; + +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.ElementType; +import java.lang.annotation.RetentionPolicy; + +/** + * Define the lazy status of a collection + * + * @author Emmanuel Bernard + */ +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface LazyCollection { + LazyCollectionOption value(); +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollectionOption.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollectionOption.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyCollectionOption.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,16 @@ +//$Id: $ +package org.hibernate.annotations; + +/** + * Lazy options available for a collection + * + * @author Emmanuel Bernard + */ +public enum LazyCollectionOption { + /** eagerly load it */ + FALSE, + /** load it when the state is requested */ + TRUE, + /** prefer extra queries over fill collection loading */ + EXTRA +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOne.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOne.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOne.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,19 @@ +//$Id: $ +package org.hibernate.annotations; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Define the lazy status of a ToOne association + * (ie OneToOne or ManyToOne) + * + * @author Emmanuel Bernard + */ +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface LazyToOne { + LazyToOneOption value(); +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOneOption.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOneOption.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/annotations/LazyToOneOption.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -0,0 +1,23 @@ +//$Id: $ +package org.hibernate.annotations; + +/** + * Lazy options available for a ToOne association + * + * @author Emmanuel Bernard + */ +public enum LazyToOneOption { + /** eagerly load the association */ + FALSE, + /** + * Lazy, give back a proxy which will be loaded when the state is requested + * This should be the prefered option + */ + PROXY, + /** Lazy, give back the real object loaded when a reference is requested + * (Bytecode enhancement is mandatory for this option, fall back to PROXY + * if the class is not enhanced) + * This option should be avoided unless you can't afford the use of proxies + */ + NO_PROXY +} Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationBinder.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/AnnotationBinder.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -82,6 +82,9 @@ import org.hibernate.annotations.TypeDefs; import org.hibernate.annotations.Where; import org.hibernate.annotations.Parent; +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.LazyToOneOption; import org.hibernate.cfg.annotations.CollectionBinder; import org.hibernate.cfg.annotations.EntityBinder; import org.hibernate.cfg.annotations.Nullability; @@ -108,6 +111,7 @@ import org.hibernate.mapping.Subclass; import org.hibernate.mapping.Table; import org.hibernate.mapping.UnionSubclass; +import org.hibernate.mapping.ToOne; import org.hibernate.persister.entity.JoinedSubclassEntityPersister; import org.hibernate.persister.entity.SingleTableEntityPersister; import org.hibernate.persister.entity.UnionSubclassEntityPersister; @@ -1016,7 +1020,7 @@ ); } - //set default values in needed + //set default values if needed if ( joinColumns == null && ( property.isAnnotationPresent( ManyToOne.class ) || property.isAnnotationPresent( OneToOne.class ) ) @@ -1178,7 +1182,6 @@ getCascadeStrategy( ann.cascade(), hibernateCascade ), joinColumns, ann.optional(), - getFetchMode( ann.fetch() ), ignoreNotFound, onDeleteCascade, mappings.getReflectionManager().toXClass( ann.targetEntity() ), propertyHolder, @@ -1662,7 +1665,7 @@ } private static void bindManyToOne( - String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional, FetchMode fetchMode, + String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional, boolean ignoreNotFound, boolean cascadeOnDelete, XClass targetEntity, PropertyHolder propertyHolder, PropertyData inferredData, boolean unique, boolean isIdentifierMapper, ExtendedMappings mappings @@ -1675,10 +1678,11 @@ else { value.setReferencedEntityName( targetEntity.getName() ); } - value.setFetchMode( fetchMode ); + defineFetchingStrategy( value, inferredData.getProperty() ); + //value.setFetchMode( fetchMode ); value.setIgnoreNotFound( ignoreNotFound ); value.setCascadeDeleteEnabled( cascadeOnDelete ); - value.setLazy( fetchMode != FetchMode.JOIN ); + //value.setLazy( fetchMode != FetchMode.JOIN ); if ( !optional ) { for ( Ejb3JoinColumn column : columns ) { column.setNullable( false ); @@ -1717,6 +1721,50 @@ propertyHolder.addProperty( prop, columns ); } + private static void defineFetchingStrategy(ToOne toOne, XProperty property) { + LazyToOne lazy = property.getAnnotation( LazyToOne.class ); + Fetch fetch = property.getAnnotation( Fetch.class ); + ManyToOne manyToOne = property.getAnnotation( ManyToOne.class ); + OneToOne oneToOne = property.getAnnotation( OneToOne.class ); + FetchType fetchType; + if (manyToOne != null) { + fetchType = manyToOne.fetch(); + } + else if (oneToOne != null) { + fetchType = oneToOne.fetch(); + } + else { + throw new AssertionFailure( "Define fetch strategy on a property not annotated with @OneToMany nor @OneToOne"); + } + if (lazy != null) { + toOne.setLazy( ! (lazy.value() == LazyToOneOption.FALSE) ); + toOne.setUnwrapProxy( (lazy.value() == LazyToOneOption.NO_PROXY) ); + } + else { + toOne.setLazy( fetchType == FetchType.LAZY ); + toOne.setUnwrapProxy( false ); + } + if (fetch != null) { + if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) { + toOne.setFetchMode( FetchMode.JOIN ); + toOne.setLazy( false ); + toOne.setUnwrapProxy( false ); + } + else if ( fetch.value() == org.hibernate.annotations.FetchMode.SELECT ) { + toOne.setFetchMode( FetchMode.SELECT ); + } + else if ( fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT ) { + throw new AnnotationException( "Use of FetchMode.SUBSELECT not allowed on ToOne associations"); + } + else { + throw new AssertionFailure( "Unknown FetchMode: " + fetch.value() ); + } + } + else { + toOne.setFetchMode( getFetchMode( fetchType ) ); + } + } + private static void bindOneToOne( String cascadeStrategy, Ejb3JoinColumn[] columns, @@ -1763,9 +1811,10 @@ else { value.setReferencedEntityName( targetEntity.getName() ); } - value.setFetchMode( fetchMode ); + defineFetchingStrategy( value, inferredData.getProperty() ); + //value.setFetchMode( fetchMode ); value.setCascadeDeleteEnabled( cascadeOnDelete ); - value.setLazy( fetchMode != FetchMode.JOIN ); + //value.setLazy( fetchMode != FetchMode.JOIN ); if ( !optional ) value.setConstrained( true ); value.setForeignKeyType( @@ -1809,7 +1858,7 @@ else { //has a FK on the table bindManyToOne( - cascadeStrategy, columns, optional, fetchMode, ignoreNotFound, cascadeOnDelete, + cascadeStrategy, columns, optional, ignoreNotFound, cascadeOnDelete, targetEntity, propertyHolder, inferredData, true, isIdentifierMapper, mappings ); @@ -1911,7 +1960,7 @@ return cascade.length() > 0 ? cascade.substring( 1 ) : "none"; } - private static FetchMode getFetchMode(FetchType fetch) { + public static FetchMode getFetchMode(FetchType fetch) { if ( fetch == FetchType.EAGER ) { return FetchMode.JOIN; } Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -11,7 +11,9 @@ import javax.persistence.AttributeOverrides; import javax.persistence.Embeddable; import javax.persistence.FetchType; +import javax.persistence.ManyToMany; import javax.persistence.MapKey; +import javax.persistence.OneToMany; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,6 +25,9 @@ import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CollectionOfElements; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.OrderBy; import org.hibernate.annotations.Sort; import org.hibernate.annotations.SortType; @@ -260,8 +265,9 @@ } //set laziness - collection.setFetchMode( fetchMode ); - collection.setLazy( fetchMode == FetchMode.SELECT ); + defineFetchingStrategy(); + //collection.setFetchMode( fetchMode ); + //collection.setLazy( fetchMode == FetchMode.SELECT ); collection.setBatchSize( batchSize ); if ( orderBy != null && hqlOrderBy != null ) { throw new AnnotationException( @@ -371,6 +377,55 @@ propertyHolder.addProperty( prop ); } + private void defineFetchingStrategy() { + LazyCollection lazy = property.getAnnotation( LazyCollection.class ); + Fetch fetch = property.getAnnotation( Fetch.class ); + OneToMany oneToMany = property.getAnnotation( OneToMany.class ); + ManyToMany manyToMany = property.getAnnotation( ManyToMany.class ); + CollectionOfElements elements = property.getAnnotation( CollectionOfElements.class ); + FetchType fetchType; + if (oneToMany != null) { + fetchType = oneToMany.fetch(); + } + else if (manyToMany != null) { + fetchType = manyToMany.fetch(); + } + else if (elements != null) { + fetchType = elements.fetch(); + } + else { + throw new AssertionFailure( "Define fetch strategy on a property not annotated with @ManyToOne nor @OneToMany nor @CollectionOfElements"); + } + if (lazy != null) { + collection.setLazy( ! (lazy.value() == LazyCollectionOption.FALSE) ); + collection.setExtraLazy( lazy.value() == LazyCollectionOption.EXTRA ); + } + else { + collection.setLazy( fetchType == FetchType.LAZY ); + collection.setExtraLazy( false ); + } + if (fetch != null) { + if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) { + collection.setFetchMode( FetchMode.JOIN ); + collection.setLazy( false ); + } + else if ( fetch.value() == org.hibernate.annotations.FetchMode.SELECT ) { + collection.setFetchMode( FetchMode.SELECT ); + } + else if ( fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT ) { + collection.setFetchMode( FetchMode.SELECT ); + collection.setSubselectLoadable(true); + collection.getOwner().setSubselectLoadableCollections(true); + } + else { + throw new AssertionFailure( "Unknown FetchMode: " + fetch.value() ); + } + } + else { + collection.setFetchMode( AnnotationBinder.getFetchMode( fetchType ) ); + } + } + private XClass getCollectionType() { if ( AnnotationBinder.isDefault( targetEntity, mappings ) ) { if ( collectionType != null ) { Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/FetchingTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/FetchingTest.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/FetchingTest.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -32,6 +32,41 @@ s.close(); } + public void testHibernateFetchingLazy() throws Exception { + Session s; + Transaction tx; + s = openSession(); + tx = s.beginTransaction(); + Person p = new Person( "Gavin", "King", "JBoss Inc" ); + Stay stay = new Stay( null, new Date(), new Date(), "A380", "Blah", "Blah" ); + Stay stay2 = new Stay( null, new Date(), new Date(), "A320", "Blah", "Blah" ); + Stay stay3 = new Stay( null, new Date(), new Date(), "A340", "Blah", "Blah" ); + stay.setOldPerson( p ); + stay2.setVeryOldPerson( p ); + stay3.setVeryOldPerson( p ); + p.addOldStay( stay ); + p.addVeryOldStay( stay2 ); + p.addVeryOldStay( stay3 ); + s.persist( p ); + tx.commit(); + s.clear(); + tx = s.beginTransaction(); + p = (Person) s.createQuery( "from Person p where p.firstName = :name" ) + .setParameter( "name", "Gavin" ).uniqueResult(); + assertFalse( Hibernate.isInitialized( p.getOldStays() ) ); + assertEquals( 1, p.getOldStays().size() ); + assertFalse( "lazy extra is failing", Hibernate.isInitialized( p.getOldStays() ) ); + s.clear(); + stay = (Stay) s.get( Stay.class, stay.getId() ); + assertTrue( ! Hibernate.isInitialized( stay.getOldPerson() ) ); + s.clear(); + stay3 = (Stay) s.get( Stay.class, stay3.getId() ); + assertTrue( "FetchMode.JOIN should overrides lazy options", Hibernate.isInitialized( stay3.getVeryOldPerson() ) ); + s.delete( stay3.getVeryOldPerson() ); + tx.commit(); + s.close(); + } + public FetchingTest(String x) { super( x ); } Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Person.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Person.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Person.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -14,7 +14,12 @@ import javax.persistence.OneToMany; import javax.persistence.Table; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; + /** * @author Emmanuel Bernard */ @@ -27,8 +32,9 @@ private String firstName; private String lastName; private String companyName; - private Collection<Stay> stays; + private Collection<Stay> oldStays; + private Collection<Stay> veryOldStays; // constructors public Person() { @@ -86,7 +92,28 @@ this.stays = stays; } + @OneToMany(cascade=CascadeType.ALL, mappedBy = "oldPerson") + @LazyCollection(LazyCollectionOption.EXTRA) + @Fetch(FetchMode.SUBSELECT) + public Collection<Stay> getOldStays() { + return oldStays; + } + public void setOldStays(Collection<Stay> oldStays) { + this.oldStays = oldStays; + } + + @OneToMany(cascade=CascadeType.ALL, mappedBy = "veryOldPerson") + @Fetch(FetchMode.SELECT) + public Collection<Stay> getVeryOldStays() { + return veryOldStays; + } + + public void setVeryOldStays(Collection<Stay> veryOldStays) { + this.veryOldStays = veryOldStays; + } + + // business logic public void addStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); @@ -102,4 +129,34 @@ this.stays = stays; } + + public void addOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { + Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); + addOldStay( stay ); + } + + public void addOldStay(Stay stay) { + Collection<Stay> stays = getOldStays(); + if ( stays == null ) { + stays = new ArrayList<Stay>(); + } + stays.add( stay ); + + this.oldStays = stays; + } + + public void addVeryOldStay(Date startDate, Date endDate, String vessel, String authoriser, String comments) { + Stay stay = new Stay( this, startDate, endDate, vessel, authoriser, comments ); + addVeryOldStay( stay ); + } + + public void addVeryOldStay(Stay stay) { + Collection<Stay> stays = getVeryOldStays(); + if ( stays == null ) { + stays = new ArrayList<Stay>(); + } + stays.add( stay ); + + this.veryOldStays = stays; + } } Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Stay.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Stay.java 2006-04-28 14:11:16 UTC (rev 9829) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/fetch/Stay.java 2006-04-28 15:16:41 UTC (rev 9830) @@ -12,6 +12,11 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.LazyToOneOption; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; + /** * @author Emmanuel Bernard */ @@ -22,6 +27,8 @@ // member declaration private int id; private Person person; + private Person oldPerson; + private Person veryOldPerson; private Date startDate; private Date endDate; private String vessel; @@ -92,6 +99,30 @@ this.person = person; } + @ManyToOne(cascade = CascadeType.ALL) + @LazyToOne(LazyToOneOption.PROXY) + @Fetch(FetchMode.SELECT) + @JoinColumn(name = "oldperson") + public Person getOldPerson() { + return oldPerson; + } + + public void setOldPerson(Person oldPerson) { + this.oldPerson = oldPerson; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @LazyToOne(LazyToOneOption.PROXY) + @Fetch(FetchMode.JOIN) + @JoinColumn(name = "veryoldperson") + public Person getVeryOldPerson() { + return veryOldPerson; + } + + public void setVeryOldPerson(Person veryOldPerson) { + this.veryOldPerson = veryOldPerson; + } + public Date getStartDate() { return startDate; } |