2010-05-28 38 views
9

Tôi có hai lớp, Test2 và Test3. Test2 có một thuộc tính test3 là một thể hiện của Test3. Nói cách khác, tôi có một liên kết OneToOne một chiều, với test2 có tham chiếu đến test3.Hibernate noob fetch join problem

Khi tôi chọn Test2 từ db, tôi có thể thấy rằng một lựa chọn riêng biệt đang được thực hiện để có được chi tiết của lớp test3 liên quan. Đây là 1 + N nổi tiếng chọn vấn đề.

Để sửa lỗi này để sử dụng một lựa chọn duy nhất, tôi đang cố gắng sử dụng lấy = tham gia chú thích, mà tôi hiểu được @Fetch (FetchMode.JOIN)

Tuy nhiên, với Truy xuất thiết lập để tham gia, tôi vẫn xem các lựa chọn riêng biệt. Dưới đây là các phần có liên quan của thiết lập của tôi ..

hibernate.cfg.xml:

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

Test2:

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

NB tôi đặt FetchType để háo hức ra khỏi sự tuyệt vọng, mặc dù nó mặc định là EAGER cho các ánh xạ OneToOne, nhưng nó không có sự khác biệt.

Cảm ơn bạn đã trợ giúp!

Chỉnh sửa: Tôi đã bỏ khá nhiều khi cố gắng sử dụng FetchMode.JOIN - bất kỳ ai cũng có thể xác nhận rằng họ đã làm việc đó tức là tạo ra một kết nối bên ngoài bên trái? Trong tài liệu tôi thấy rằng "Thông thường, tài liệu ánh xạ không được sử dụng để tùy chỉnh tìm nạp. Thay vào đó, chúng tôi giữ nguyên hành vi mặc định và ghi đè lên giao dịch cụ thể, sử dụng tìm nạp tham gia bên trái trong HQL"

Nếu tôi làm tìm nạp tham gia bên trái thay thế:

truy vấn = session.createQuery ("từ Test2 t2 tìm nạp bên trái t2.test3");

sau đó tôi thực sự nhận được kết quả tôi muốn - tức là tham gia bên ngoài bên trái trong truy vấn.

Chỉnh sửa số 2:

Guys, cảm ơn bạn rất nhiều vì phản hồi của bạn. Bây giờ tôi muốn đi sâu vào vấn đề này. Tôi thường thấy rằng khi tôi điều tra điều gì đó, tôi sẽ học được nhiều hơn tôi nghĩ.

Một điều tôi đã học - Tôi đã chạy trên các phiên bản cũ của ngủ đông vì tôi không nhận ra rằng kho lưu trữ maven đã lỗi thời. Bây giờ tôi đang nối vào kho lưu trữ jboss, và tôi có các phiên bản mới nhất của các chú thích ngủ đông và ngủ đông - 3.5.1-Final trong cả hai trường hợp.

Tôi đã thiết lập một trường hợp thử nghiệm nhỏ để đơn giản hóa nó nhiều nhất có thể - Tôi vẫn gặp sự cố trong 3.5.1-cuối cùng, tho 'Tôi chắc chắn 99% nó chỉ là một cái gì đó ngu ngốc Tôi không thiết lập đúng, đặc biệt là Ross, cho rằng bạn đã nhận nó để làm việc (nhờ dành thời gian để thử nó bằng cách này)

Vì vậy, tôi có các lớp này (toàn văn thời điểm này)

class 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; 
    } 
} 

class 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; 
    } 
} 

toàn hibernate.cfg.xml My

<?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> 

Việc thử nghiệm lớp

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; 
    } 

} 

Và cuối cùng là dữ liệu ghi nhận cho thấy sẽ chọn thêm để lấy lại lớp liên

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] 

Chỉnh sửa số 3:

Nếu tôi làm những việc Ross 'cách, với một tải trọng, một bên ngoài bên ngoài tham gia được tạo ra. Nếu tôi làm điều đó với một danh sách, các lựa chọn riêng biệt được phát hành. Đây là mã có liên quan. Chỉ thay đổi điều này tái tạo sự khác biệt về hành vi:

/* 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()); 

Tôi đoán nó có thể được gọi là 'lỗi'. Như tôi đã đề cập trước đó, trong tài liệu, họ nói 'bình thường' để chỉ định chế độ tìm nạp trong HQL chứ không phải trong ánh xạ, mà tôi đang nghĩ có thể có nghĩa là cách HQL có lưu lượng truy cập chân nhiều hơn. .?

(bằng cách này tôi đã thêm một 'tên' thêm lĩnh vực A và B khác ngủ đông sẽ tối ưu hóa lấy vì nó có thể nhận được tất cả B chỉ từ khoá ngoại trên A)

+0

Chỉ cần suy nghĩ: Tôi thấy rằng chú thích của bạn nằm trên bộ thu thập dữ liệu - đây có phải là cách tương tự cho tất cả các thành viên khác của Test2 không? Nếu không, sửa chữa nó có thể giải quyết vấn đề của bạn. –

+0

Cảm ơn Peter. Có, tất cả chúng đều trên getters (nhưng tôi đã mắc sai lầm này trong quá khứ và nó đã phá vỡ mọi thứ ..) – Jeremy

+0

Đáng buồn thay, iterate không hoạt động - thực ra nó tệ hơn! Bây giờ nó thực hiện lựa chọn ban đầu, nó cung cấp cho nó các id đối tượng, sau đó nó lựa chọn cho mỗi đối tượng liên quan, nhưng thực hiện một phép nối ngoài bên trái thông qua bảng liên kết, thay vì chỉ đi thẳng đến liên kết - một lựa chọn riêng biệt phức tạp hơn! (xem bình luận của tôi về câu trả lời của bạn dưới đây) Oh well. Tôi nghĩ rằng nó sẽ HQL để được an toàn, đó là có lẽ tốt hơn vì nó rõ ràng hơn .. – Jeremy

Trả lời

4

Khi tôi chọn Test2 từ db, tôi có thể thấy rằng một lựa chọn riêng biệt đang được thực hiện để có được những thông tin chi tiết của lớp test3 liên quan.

Tôi rất thích mã của câu trả lời khác bởi vì đó là những gì tôi thấy khi kiểm tra mã bạn đang hiển thị, nó tạo hai lựa chọn cho from Test2.

Tôi đang sử dụng các phụ thuộc sau:

  • org.hibernate: ngủ đông-EntityManager: jar: 3.4.0.GA: biên dịch
  • org.hibernate: EJB3-kiên trì: jar: 1.0. 2.GA:compile
  • org.hibernate: ngủ đông-commons-chú thích: jar: 3.1.0.GA: biên dịch
  • org.hibernate: ngủ đông-chú thích: jar: 3.4.0.GA: biên dịch
  • org.hibernate: hibernate-core: jar: 3.3.0.SP1: biên dịch

Tôi đặt FetchType thành EAGER trong tuyệt vọng, mặc dù mặc định mặc định là EAGER đối với ánh xạ OneToOne nhưng không có sự khác biệt.

Điều này không có tác động nếu bạn sử dụng chú thích Hibernate vì chú thích Hibernate ghi đè tùy chọn tìm nạp EJB3. Xem 2.4.5.1. Lazy options and fetching modes.

+0

Cảm ơn bạn đã dành thời gian, Pascal :-) Thật tốt để có được một số bản sao. Tôi đã đơn giản hóa trường hợp thử nghiệm ở trên. Tôi đoán hoặc là có một lỗi trong thiết lập của tôi rằng ai đó sẽ phát hiện ra, hoặc có một cái gì đó buồn cười trong ngủ đông trong tình huống này, mặc dù không phải trong một mà Ross trình bày. – Jeremy

+0

Tôi chấp nhận câu trả lời của bạn là chính xác, một phần để kiểm tra vấn đề (mà Ross cũng đã làm, và tôi cũng đánh dấu câu trả lời của anh ấy nếu tôi có thể), nhưng cũng vì sao chép nó, bạn đã ngăn cản tôi phát điên :-) – Jeremy

2

Tôi tạo ra một ứng dụng rất đơn giản để kiểm tra kịch bản bạn đang nhận được và mã của bạn sẽ hoạt động (nó đang làm việc cho tôi). Điều duy nhất tôi đã cố gắng sẽ cho tôi nhiều câu lệnh chọn là thiết lập max_fetch_depth thành 0. Nếu được đặt thành 2 (hoặc không được cấu hình), tôi nhận được phép nối ngoài bên trái trong truy vấn của tôi. Bạn đang sử dụng phiên bản hibernate nào? Tôi đang sử dụng 3.4.0.GA.

EDIT: Dưới đây là ứng dụng đơn giản tôi đã sử dụng (với các phiên bản tương tự được đề cập bởi 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> 

Người tổ chức - giữ nó đơn giản chỉ có @OneToOne, thêm JoinColumn, vv không có sự khác biệt.

@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; 
    } 
} 

thử nghiệm đơn giản:

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()); 
} 

Output:

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

Cảm ơn bạn đã dành thời gian để kiểm tra điều này, Ross. Tôi thực sự đánh giá cao nó .. Tôi đã dán mã đầy đủ của một thử nghiệm nhỏ hơn. Tôi sẽ thực sự quan tâm nếu nó hoạt động OK trong thiết lập của bạn. Nó không hoạt động trong tôi, thậm chí dưới 3.5.1-Final, nhưng nó có thể là một cái gì đó trong mã của tôi, vì vậy tôi đã dán tất cả của nó .. Cảm ơn :-) – Jeremy

+0

OK - chúng tôi đang theo dõi này. Nếu tôi làm một tải, như bạn làm, tôi nhận được hành vi bên ngoài tham gia bên ngoài. Tuy nhiên, nếu tôi làm danh sách(), và sau đó nhận được đối tượng đầu tiên trong danh sách, nó có hai lựa chọn - xem Chỉnh sửa số 3 của tôi trong câu hỏi ban đầu – Jeremy

+0

Có Tôi nhận được kết quả tương tự như bạn. Thay vì sử dụng danh sách hãy thử sử dụng iterate - Tôi đã thử và dường như làm việc – Ross

17

Là một phương pháp chưng cất:

@Fetch (JOIN) sẽ bị bỏ qua nếu bạn sử dụng giao diện truy vấn (ví dụ .: session.createQuery()) nhưng nó sẽ được sử dụng đúng cách nếu bạn sử dụng giao diện tiêu chuẩn.

Đây thực tế là lỗi trong Hibernate chưa được giải quyết. Thật không may bởi vì rất nhiều ứng dụng sử dụng giao diện truy vấn và không thể di chuyển dễ dàng đến giao diện tiêu chí.

Nếu bạn sử dụng giao diện truy vấn, bạn luôn phải thêm các câu lệnh JOIN FETCH vào HQL theo cách thủ công.

+0

Tôi đã chết để biết tại sao điều này đang xảy ra và nó không được đề cập ở bất cứ đâu. Cảm ơn bạn. Công ty của tôi và bản thân tôi nợ bạn rất nhiều. –

+2

@EyadEbrahim thực sự là tài liệu rõ ràng về nó: * "Đại diện cho chiến lược tìm nạp liên kết. Điều này được sử dụng cùng với API tiêu chí để chỉ định chiến lược tìm nạp thời gian. Đối với truy vấn HQL, hãy sử dụng từ khóa FETCH thay thế." * Http: // docs. jboss.org/hibernate/core/3.3/api/org/hibernate/FetchMode.html – JCasso

+0

một lời nhắc khác mà tôi nên đọc trước khi nói. –