2010-05-28 13 views
9

Tengo dos clases, Test2 y Test3. Test2 tiene un atributo test3 que es una instancia de Test3. En otras palabras, tengo una asociación OneToOne unidireccional, con test2 que hace referencia a test3.Hibernate noob fetch join problem

Cuando selecciono Test2 desde el archivo db, puedo ver que se está realizando una selección por separado para obtener los detalles de la clase test3 asociada. Este es el famoso problema 1 + N selecciona.

Para solucionar este problema de usar una sola selección, estoy tratando de utilizar el fetch = unirse a la anotación, que entiendo que ser @Fetch (FetchMode.JOIN)

Sin embargo, por medio de FETCH punto de unirse, todavía ver selecciones separadas Estas son las partes pertinentes de mi configuración ..

hibernate.cfg.xml:

<property name="max_fetch_depth">2</property> 

Prueba2:

public class Test2 { 
@OneToOne (cascade=CascadeType.ALL , fetch=FetchType.EAGER) 
@JoinColumn (name="test3_id") 
@Fetch(FetchMode.JOIN) 
public Test3 getTest3() { 
    return test3; 
} 

NB I establece la fetchType a EAGER de la desesperación, a pesar de que el valor predeterminado es EAGER de todos modos para las asignaciones OneToOne, pero no hizo ninguna diferencia.

¡Gracias por cualquier ayuda!

Editar: He dejado de intentar usar FetchMode.JOIN - ¿alguien puede confirmar que lo han conseguido, es decir, producir una unión externa izquierda? En los documentos veo que "Normalmente, el documento de asignación no se usa para personalizar la obtención. En cambio, mantenemos el comportamiento predeterminado y lo reemplazamos para una transacción en particular, usando la búsqueda de unión izquierda en HQL"

Si lo hago una búsqueda de unión a la izquierda en su lugar:

query = session.createQuery ("de Test2 t2 left join fetch t2.test3");

entonces sí obtengo los resultados que quiero, es decir, una combinación externa izquierda en la consulta.

Editar número 2:

chicos, muchas gracias por sus respuestas. Ahora quiero llegar al fondo de esto. Normalmente encuentro que cuando investigo algo, termino aprendiendo mucho más de lo que pensaba.

Una cosa que ya he aprendido: me estaba ejecutando en viejas versiones de hibernación porque no me di cuenta de que el repositorio de maven estaba desactualizado. Ahora estoy conectado al repositorio de jboss también, y tengo las últimas versiones de hibernación y anotaciones de hibernación: 3.5.1-Final en ambos casos.

He creado un pequeño estuche de prueba que lo simplifica tanto como puedo: sigo viendo el problema en 3.5.1-Final, aunque estoy 99% seguro de que es solo algo estúpido que no estoy configurando bien, especialmente Ross, dado que lo tienes para trabajar (gracias por tomarte el tiempo de probarlo por cierto)

Así que tienen estas clases (texto completo esta vez)

Clase A

package com.play.hibernate2; 

import javax.persistence.CascadeType; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.OneToOne; 

import org.hibernate.annotations.Fetch; 
import org.hibernate.annotations.FetchMode; 

@Entity 
public class A { 

    private Integer id; 
    private B b; 

    public A() { 
     super(); 
    } 

    @Id 
    @GeneratedValue 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    @OneToOne (cascade=CascadeType.ALL) 
    @Fetch(FetchMode.JOIN) 
    public B getB() { 
     return b; 
    } 

    public void setB(B b) { 
     this.b = b; 
    } 
} 

Clase B

package com.play.hibernate2; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 

@Entity 
public class B { 

    private Integer id; 

    public B() { 
     super(); 
    } 

    @Id 
    @GeneratedValue 
    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 
} 

todo mi hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
     "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 

<hibernate-configuration> 

    <session-factory> 

     <!-- Database connection settings --> 
     <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 
     <!-- <property name="connection.driver_class">com.p6spy.engine.spy.P6SpyDriver</property> --> 
     <property name="connection.url">jdbc:mysql://localhost:3306/play</property> 
     <property name="connection.username">play</property> 
     <property name="connection.password">play</property> 

     <!-- JDBC connection pool (use the built-in) --> 
     <property name="connection.pool_size">1</property> 

     <!-- SQL dialect --> 
     <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 

     <!-- Enable Hibernate's automatic session context management --> 
     <property name="current_session_context_class">thread</property> 

     <!-- Disable the second-level cache --> 
     <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 

     <!-- Echo all executed SQL to stdout --> 
     <property name="show_sql">true</property> 
     <property name="generate_statistics">true</property> 
     <!-- 
     <property name="cache.use_structured_entries">true</property> 
     <property name="cache.use_query_cache">true</property> 
     --> 
     <property name="format_sql">true</property> 
     <property name="use_sql_comments">true</property> 

     <!-- I think this may fix my individual requests for OneToOne problem --> 
     <property name="max_fetch_depth">2</property> 
     <!-- <property name="default_batch_fetch_size">10</property> --> 

    </session-factory>  

</hibernate-configuration> 

La prueba de clase

package com.play.hibernate2; 

import java.util.List; 
import java.util.Map; 


import org.hibernate.FlushMode; 
import org.hibernate.Query; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.AnnotationConfiguration; 
import org.hibernate.tool.hbm2ddl.SchemaExport; 

public class RunTests4 { 
    private SessionFactory sessionFactory; 

    public static void main(String[] args){ 
     RunTests4 d = new RunTests4(); 
     d.run3(); 
    } 
    public void run3(){ 

     Session session = getSession(); 
     session.beginTransaction(); 

     createEntities(session); 

     session.getTransaction().commit(); 

     System.out.println("NOW WITH A NEW TRANSACTION"); 
     session = getSession(); 
     session.beginTransaction(); 

     Query query = session.createQuery("from A"); 
     List results = query.list(); 
     for (int i=0; i<results.size(); i++){ 
      System.out.println("Row "+i+" was:"); 
      A a = (A)results.get(i); 
      System.out.println("Result "+i); 
      System.out.println(a.toString()); 
     } 

     session.getTransaction().commit(); 


    } 
    public void createEntities(Session session){ 
     for (int i=0; i<2; i++){ 
      A a = new A(); 

      B b = new B(); 

      a.setB(b); 

      session.save(a); 

     } 

    } 
    public Session getSession(){ 
     if (sessionFactory == null){ 
      AnnotationConfiguration config = new AnnotationConfiguration(); 
      config.addAnnotatedClass(A.class); 
      config.addAnnotatedClass(B.class); 
      config.configure(); 
      new SchemaExport(config).create(true,true); 

      sessionFactory = config.buildSessionFactory(); 
     } 
     Session session = sessionFactory.getCurrentSession(); 

     return session; 
    } 

} 

Y, finalmente, la salida del registro que muestra los selecciona adicionales para volver a la clase asociada

2 [main] INFO org.hibernate.cfg.annotations.Version - Hibernate Annotations 3.5.1-Final 
23 [main] INFO org.hibernate.cfg.Environment - Hibernate 3.5.1-Final 
28 [main] INFO org.hibernate.cfg.Environment - hibernate.properties not found 
32 [main] INFO org.hibernate.cfg.Environment - Bytecode provider name : javassist 
37 [main] INFO org.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling 
160 [main] INFO org.hibernate.annotations.common.Version - Hibernate Commons Annotations 3.2.0.Final 
176 [main] INFO org.hibernate.cfg.Configuration - configuring from resource: /hibernate.cfg.xml 
176 [main] INFO org.hibernate.cfg.Configuration - Configuration resource: /hibernate.cfg.xml 
313 [main] INFO org.hibernate.cfg.Configuration - Configured SessionFactory: null 
338 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.MySQLDialect 
462 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.Test2 
545 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.Test2 on table Test2 
649 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.Test3 
650 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.Test3 on table Test3 
651 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.A 
651 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.A on table A 
653 [main] INFO org.hibernate.cfg.AnnotationBinder - Binding entity from annotated class: com.play.hibernate2.B 
653 [main] INFO org.hibernate.cfg.annotations.EntityBinder - Bind entity com.play.hibernate2.B on table B 
678 [main] INFO org.hibernate.cfg.AnnotationConfiguration - Hibernate Validator not found: ignoring 
687 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - Running hbm2ddl schema export 
688 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - exporting generated schema to database 
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Using Hibernate built-in connection pool (not for production use!) 
691 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate connection pool size: 1 
698 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode: false 
711 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/play 
711 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - connection properties: {user=play, password=****} 

    alter table A 
     drop 
     foreign key FK412E010759 

    alter table Test2 
     drop 
     foreign key FK4CF5DC04B7E1B79 

    drop table if exists A 

    drop table if exists B 

    drop table if exists Test2 

    drop table if exists Test3 

    create table A (
     id integer not null auto_increment, 
     b_id integer, 
     primary key (id) 
    ) 

    create table B (
     id integer not null auto_increment, 
     primary key (id) 
    ) 

    create table Test2 (
     id integer not null auto_increment, 
     name varchar(255), 
     value integer not null, 
     test3_id integer, 
     primary key (id) 
    ) 

    create table Test3 (
     id integer not null auto_increment, 
     name varchar(255), 
     value integer not null, 
     primary key (id) 
    ) 

    alter table A 
     add index FK412E010759 (b_id), 
     add constraint FK412E010759 
     foreign key (b_id) 
     references B (id) 

    alter table Test2 
     add index FK4CF5DC04B7E1B79 (test3_id), 
     add constraint FK4CF5DC04B7E1B79 
     foreign key (test3_id) 
     references Test3 (id) 
2562 [main] INFO org.hibernate.tool.hbm2ddl.SchemaExport - schema export complete 
2564 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:mysql://localhost:3306/play 
2571 [main] INFO org.hibernate.cfg.search.HibernateSearchEventListenerRegister - Unable to find org.hibernate.search.event.FullTextIndexEventListener on the classpath. Hibernate Search is not enabled. 
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Using Hibernate built-in connection pool (not for production use!) 
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - Hibernate connection pool size: 1 
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - autocommit mode: false 
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/play 
2575 [main] INFO org.hibernate.connection.DriverManagerConnectionProvider - connection properties: {user=play, password=****} 
2622 [main] INFO org.hibernate.cfg.SettingsFactory - RDBMS: MySQL, version: 5.1.30 
2622 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.1.9 (Revision: ${svn.Revision}) 
2633 [main] INFO org.hibernate.dialect.Dialect - Using dialect: org.hibernate.dialect.MySQLDialect 
2635 [main] INFO org.hibernate.engine.jdbc.JdbcSupportLoader - Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4 
2636 [main] INFO org.hibernate.transaction.TransactionFactoryFactory - Using default transaction strategy (direct JDBC transactions) 
2638 [main] INFO org.hibernate.transaction.TransactionManagerLookupFactory - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended) 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic flush during beforeCompletion(): disabled 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Automatic session close at end of transaction: disabled 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch size: 15 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC batch updates for versioned data: disabled 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Scrollable result sets: enabled 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - JDBC3 getGeneratedKeys(): enabled 
2638 [main] INFO org.hibernate.cfg.SettingsFactory - Connection release mode: auto 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Maximum outer join fetch depth: 2 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Default batch fetch size: 1 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Generate SQL with comments: enabled 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Order SQL updates by primary key: disabled 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Order SQL inserts for batching: disabled 
2639 [main] INFO org.hibernate.cfg.SettingsFactory - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory 
2641 [main] INFO org.hibernate.hql.ast.ASTQueryTranslatorFactory - Using ASTQueryTranslatorFactory 
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Query language substitutions: {} 
2641 [main] INFO org.hibernate.cfg.SettingsFactory - JPA-QL strict compliance: disabled 
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Second-level cache: enabled 
2641 [main] INFO org.hibernate.cfg.SettingsFactory - Query cache: disabled 
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Cache region factory : org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge 
2644 [main] INFO org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge - Cache provider: org.hibernate.cache.NoCacheProvider 
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Optimize cache for minimal puts: disabled 
2644 [main] INFO org.hibernate.cfg.SettingsFactory - Structured second-level cache entries: disabled 
2648 [main] INFO org.hibernate.cfg.SettingsFactory - Echoing all SQL to stdout 
2648 [main] INFO org.hibernate.cfg.SettingsFactory - Statistics: enabled 
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Deleted entity synthetic identifier rollback: disabled 
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Default entity-mode: pojo 
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Named query checking : enabled 
2649 [main] INFO org.hibernate.cfg.SettingsFactory - Check Nullability in Core (should be disabled when Bean Validation is on): enabled 
2697 [main] INFO org.hibernate.impl.SessionFactoryImpl - building session factory 
2796 [Finalizer] INFO org.hibernate.connection.DriverManagerConnectionProvider - cleaning up connection pool: jdbc:mysql://localhost:3306/play 
2929 [main] INFO org.hibernate.impl.SessionFactoryObjectFactory - Not binding factory to JNDI, no JNDI name configured 
Hibernate: 
    /* insert com.play.hibernate2.B 
     */ insert 
     into 
      B 

     values 
      () 
Hibernate: 
    /* insert com.play.hibernate2.A 
     */ insert 
     into 
      A 
      (b_id) 
     values 
      (?) 
Hibernate: 
    /* insert com.play.hibernate2.B 
     */ insert 
     into 
      B 

     values 
      () 
Hibernate: 
    /* insert com.play.hibernate2.A 
     */ insert 
     into 
      A 
      (b_id) 
     values 
      (?) 
NOW WITH A NEW TRANSACTION 
Hibernate: 
    /* 
from 
    A */ select 
     a0_.id as id2_, 
     a0_.b_id as b2_2_ 
    from 
     A a0_ 
Hibernate: 
    /* load com.play.hibernate2.B */ select 
     b0_.id as id3_0_ 
    from 
     B b0_ 
    where 
     b0_.id=? 
Hibernate: 
    /* load com.play.hibernate2.B */ select 
     b0_.id as id3_0_ 
    from 
     B b0_ 
    where 
     b0_.id=? 
Row 0 was: 
Result 0 
[email protected] 
Row 1 was: 
Result 1 
[email protected] 

Editar número 3:

Si hago las cosas La forma de Ross, con una carga, se crea una unión externa izquierda. Si lo hago con una lista, se emiten selecciones separadas. Aquí está el código relevante. Solo cambiando esto se reproduce la diferencia de comportamiento:

/* generates the left outer join 
    A a = (A)session.load(A.class,1); 
    System.out.println(a.getId()+" = "+a.getB().getName()); 
    */ 

    // Creates separate selects for each object b associated with each a 
    Query query = session.createQuery("from A"); 
    List results = query.list(); 
    A a = (A)results.get(0); 
    System.out.println(a.getId()+" = "+a.getB().getName()); 

Supongo que se podría llamar un 'error'. Como mencioné anteriormente, en los documentos, dicen que es 'habitual' especificar el modo de búsqueda en el HQL en lugar de en el mapeo, lo que creo que podría significar que el modo HQL ha tenido más tráfico peatonal para acotarlo. .?

(por cierto me añade un campo adicional 'nombre' de A y B de otro modo hibernación optimiza el recuperar, ya que puede obtener todos los B sólo de la clave externa en A)

+0

Solo un pensamiento: Veo que sus anotaciones están en el getter - ¿es esta la misma manera para todos los demás miembros de Test2? De lo contrario, solucionarlo puede resolver su problema. –

+0

Gracias Peter. Sí, todos están en buscadores (pero he cometido este error en el pasado y rompió las cosas ...) – Jeremy

+0

Lamentablemente, la iteración no funciona, de hecho ¡es peor! Ahora hace la selección inicial, que le da los ID de los objetos, luego selecciona los objetos asociados, pero hace una combinación externa izquierda a través de la tabla del asociator, en lugar de ir directamente al asociado, ¡una selección separada más complicada! (ver mi comentario en su respuesta a continuación) Oh bien. Creo que va a HQL estar a salvo, lo cual es quizás mejor ya que es más explícito. – Jeremy

Respuesta

4

Cuando selecciono Prueba2 de la db, puedo ver que un selecto separada se está haciendo para obtener los detalles de la clase test3 asociada.

Estoy muy interesado por el código de la otra respuesta, porque eso es lo que estoy viendo demasiado cuando se prueba el código que está mostrando, genera dos selecciona para un from Test2.

estoy usando las siguientes dependencias:

  • org.hibernate: hibernate-EntityManager: Tarro: 3.4.0.GA: compilar
  • org.hibernate: ejb3-persistencia: Tarro: 1.0. 2.GA:compile
  • org.hibernate: hibernate-commons-anotaciones: tarro: 3.1.0.GA: compilar
  • org.hibernate: hibernate-anotaciones: tarro: 3.4.0.GA: compilar
  • org.hibernate: hibernate-core: jar: 3.3.0.SP1: compilar

que establezca la fetchType a EAGER de la desesperación, a pesar de que por defecto es de todos modos para EAGER asignaciones OneToOne, pero no había ninguna diferencia.

Esto no tiene ningún impacto si utiliza anotaciones de Hibernate porque las anotaciones de Hibernate anulan las opciones de recuperación de EJB3. Ver 2.4.5.1. Lazy options and fetching modes.

+0

Gracias por tomarse el tiempo, Pascal :-) Eso es bueno para obtener alguna replicación. He simplificado el caso de prueba anterior. Supongo que hay un error en mi configuración que alguien detectará, o hay algo raro en la hibernación en esta situación, aunque no en el que Ross presenta. – Jeremy

+0

Acepté su respuesta como correcta, en parte para probar el problema (que Ross también hizo, y marcaría su respuesta también si pudiera), pero también porque al reproducirla, me impidió volverme loco :-) – Jeremy

2

he creado una aplicación muy sencilla para probar el escenario que está recibiendo y su código debería funcionar (me funciona). Lo único que he probado que me dará varias sentencias de selección es establecer max_fetch_depth en 0. Si se establece en 2 (o no está configurado) obtengo la combinación externa izquierda en mi consulta. ¿Qué versión de Hibernate estás usando? Estoy usando 3.4.0.GA.

EDIT: A continuación se muestra la simple aplicación utilicé (con las mismas versiones mencionadas por Pascal):

CFG:

<hibernate-configuration> 
    <session-factory> 
     <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property> 
     <property name="hibernate.connection.url">jdbc:hsqldb:hibscribs</property> 
     <property name="hibernate.connection.username">sa</property> 
     <property name="hibernate.connection.password"></property> 
     <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property> 
     <property name="show_sql">true</property> 
     <property name="format_sql">true</property> 
     <property name="hbm2ddl.auto">create-drop</property> 
     <property name="current_session_context_class">thread</property> 
     <!-- property name="max_fetch_depth">0</property--><!-- uncomment to see where 2 selects are used instead of join --> 

     <mapping class="com.mydomain.bo.Person" /> 
     <mapping class="com.mydomain.bo.Phone" /> 

    </session-factory> 
</hibernate-configuration> 

entidad Persona - mantuvo simple suficiente @OneToOne, añadiendo JoinColumn, etc. no hizo diferencia.

@Entity 
@Table(name="person") 
public class Person { 
    private Long id; 
    private String name; 
    private Phone phone; 

    @Id 
    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 
    public void setName(String name) { 
     this.name = name; 
    } 

    @OneToOne(cascade=CascadeType.ALL) 
    public Phone getPhone() { 
     return phone; 
    } 

    public void setPhone(Phone phone) { 
     this.phone = phone; 
    } 
} 

.

@Entity 
@Table(name="phone") 
public class Phone { 
    private Long id; 
    private String number; 

    @Id 
    public Long getId() { 
     return id; 
    } 
    public void setId(Long id) { 
     this.id = id; 
    } 

    public String getNumber() { 
     return number; 
    } 
    public void setNumber(String number) { 
     this.number = number; 
    } 
} 

Prueba simple:

SessionFactory session = HibernateUtil.getSessionFactory(); 
Session sess = session.getCurrentSession(); 
Transaction tx = sess.beginTransaction(); 

Phone phone = new Phone(); 
phone.setId(1L); 
phone.setNumber("1234567"); 

Person person = new Person(); 
person.setId(1L); 
person.setName("Bob"); 
person.setPhone(phone); 

sess.save(person); 

tx.commit(); 

sess = session.openSession(); 

//Person p1 = (Person)sess.load(Person.class,1L); 
//System.out.println(p1.getPhone().getNumber()); 

// changed the above code to use the Criteria interface below: 
Criteria criteria = sess.createCriteria(Person.class); 
List<Person> results = criteria.list(); 
for (int i=0; i<results.size(); i++){ 
    Person p = (Person)results.get(i); 
    System.out.println(p.getPhone().getNumber()); 
} 

Salida:

Hibernate: 
    select 
     phone_.id, 
     phone_.number as number1_ 
    from 
     phone phone_ 
    where 
     phone_.id=? 
Hibernate: 
    insert 
    into 
     phone 
     (number, id) 
    values 
     (?, ?) 
Hibernate: 
    insert 
    into 
     person 
     (name, phone_id, id) 
    values 
     (?, ?, ?) 
Hibernate: 
    select 
     person0_.id as id0_1_, 
     person0_.name as name0_1_, 
     person0_.phone_id as phone3_0_1_, 
     phone1_.id as id1_0_, 
     phone1_.number as number1_0_ 
    from 
     person person0_ 
    left outer join 
     phone phone1_ 
      on person0_.phone_id=phone1_.id 
    where 
     person0_.id=? 
1234567 
+0

Gracias por tomarse el tiempo para probar esto, Ross. Realmente lo aprecio ... He pegado el código completo de una prueba más pequeña. Estaría realmente interesado si funciona bien en tu configuración. No funciona en el mío, incluso por debajo de 3.5.1-Final, pero puede ser algo en mi código, así que lo he pegado todo ... Gracias :-) – Jeremy

+0

OK - estamos en la pista de esto. Si hago una carga, como lo haces, obtengo el comportamiento de combinación externa izquierda. Sin embargo, si hago una lista(), y luego obtengo el primer objeto en la lista, hace dos selecciones - vea mi número de edición 3 en la pregunta inicial – Jeremy

+0

Sí, estoy obteniendo los mismos resultados que usted. En lugar de usar la lista, intente usar iterar, lo intenté y pareció funcionar – Ross

17

Como destilación:

@Fetch (JOIN) será ignorado si se utiliza la interfaz de consulta (ej .: session.createQuery()) pero se usarán correctamente si se utiliza la interfaz Criterios.

Esto es prácticamente un error en Hibernate que nunca se resolvió. Es desafortunado porque muchas aplicaciones usan la interfaz de Consulta y no se pueden migrar fácilmente a la interfaz de Criteria.

Si utiliza la interfaz de consulta siempre debe agregar instrucciones JOIN FETCH al HQL manualmente.

+0

Me moría de ganas de saber por qué sucede esto y no fue mencionado en ningún lado. Gracias señor. Mi compañía y yo le debemos un gran negocio. –

+2

@EyadEbrahim en realidad la documentación es clara al respecto: * "Representa una estrategia de búsqueda de asociación. Se usa junto con la API Criteria para especificar estrategias de búsqueda de tiempo de ejecución. Para las consultas HQL, use la palabra clave FETCH en su lugar." * Http: // docs. jboss.org/hibernate/core/3.3/api/org/hibernate/FetchMode.html – JCasso

+0

otro recordatorio que debería leer antes de hablar. –