简体   繁体   English

Hibernate noob获取连接问题

[英]Hibernate noob fetch join problem

I have two classes, Test2 and Test3. 我有两个类,Test2和Test3。 Test2 has an attribute test3 that is an instance of Test3. Test2有一个属性test3,它是Test3的一个实例。 In other words, I have a unidirectional OneToOne association, with test2 having a reference to test3. 换句话说,我有一个单向的OneToOne关联,test2引用了test3。

When I select Test2 from the db, I can see that a separate select is being made to get the details of the associated test3 class. 当我从db中选择Test2时,我可以看到正在进行单独的选择以获取相关test3类的详细信息。 This is the famous 1+N selects problem. 这是着名的1 + N选择问题。

To fix this to use a single select, I am trying to use the fetch=join annotation, which I understand to be @Fetch(FetchMode.JOIN) 要修复此问题以使用单个选择,我尝试使用fetch = join注释,我理解为@Fetch(FetchMode.JOIN)

However, with fetch set to join, I still see separate selects. 但是,如果将fetch设置为join,我仍会看到单独的选择。 Here are the relevant portions of my setup.. 以下是我的设置的相关部分..

hibernate.cfg.xml: hibernate.cfg.xml中:

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

Test2: 测试2:

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

NB I set the FetchType to EAGER out of desperation, even though it defaults to EAGER anyway for OneToOne mappings, but it made no difference. NB我将FetchType设置为EAGER绝望,即使它无论如何都默认为EAGER OneToOne映射,但它没有任何区别。

Thanks for any help! 谢谢你的帮助!

Edit: I've pretty much given up on trying to use FetchMode.JOIN - can anyone confirm that they have got it to work ie produce a left outer join? 编辑:我几乎放弃了尝试使用FetchMode.JOIN - 任何人都可以确认他们已经让它工作,即产生左外连接? In the docs I see that "Usually, the mapping document is not used to customize fetching. Instead, we keep the default behavior, and override it for a particular transaction, using left join fetch in HQL" 在文档中,我看到“通常,映射文档不用于自定义提取。相反,我们保留默认行为,并使用HQL中的左连接提取覆盖特定事务”

If I do a left join fetch instead: 如果我做一个左连接取代:

query = session.createQuery("from Test2 t2 left join fetch t2.test3"); query = session.createQuery(“来自Test2 t2 left join fetch t2.test3”);

then I do indeed get the results I want - ie a left outer join in the query. 然后我确实得到了我想要的结果 - 即查询中的左外连接。

Edit number 2: 编辑2:

Guys, thank you so much for your responses. 伙计们,非常感谢您的回复。 Now I want to get to the bottom of this. 现在我想深究这一点。 I usually find that when I investigate something, I end up learning a lot more than I thought I would. 我经常发现,当我调查某些东西时,我最终学到的东西比我想象的要多得多。

One thing I've learned already - I was running on old builds of hibernate because I didn't realize that the maven repository was out of date. 我已经学到了一件事 - 我正在运行旧的hibernate构建,因为我没有意识到maven存储库已经过时了。 Now I'm hooked up to the jboss repository too, and I have the latest versions of hibernate and hibernate annotations - 3.5.1-Final in both cases. 现在我也连接到jboss存储库,我有最新版本的hibernate和hibernate注释 - 在两种情况下都是3.5.1-Final。

I've set up a small test case that simplifies it as much as I can - I'm still seeing the problem in 3.5.1-Final, tho' I'm 99% certain it's just something stupid I'm not setting up right, especially Ross, given that you got it to work (thanks for taking the time to try it by the way) 我已经设置了一个小的测试用例,尽可能地简化它 - 我仍然在3.5.1-Final中看到问题,因为'我99%肯定这只是一些愚蠢我没有设置是的,特别是罗斯,因为你得到它的工作(感谢花时间尝试顺便说一句)

So I have these classes (full text this time) 所以我有这些课程(这次是全文)

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

My whole hibernate.cfg.xml 我的整个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>

The testing class 测试课

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

}

And finally the log output showing the extra selects to get back the associated class 最后,日志输出显示额外的选择以返回关联的类

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
com.play.hibernate2.A@351daa0e
Row 1 was:
Result 1
com.play.hibernate2.A@2e879860

Edit Number 3: 编辑3:

If I do things Ross' way, with a load, a left outer join gets created. 如果我以罗斯的方式做事,加载时会创建一个左外连接。 If I do it with a list, separate selects are issued. 如果我使用列表执行此操作,则会发出单独的选择。 Here's the relevant code. 这是相关的代码。 Only changing this reproduces the difference in behavior: 只有改变它才能重现行为上的差异:

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

I guess it might be called a 'bug'. 我猜它可能被称为'bug'。 As I mentioned earlier, in the docs, they say it's 'usual' to specify the fetch mode in the HQL rather than in the mapping, which I'm thinking might mean that the HQL way has had more foot traffic to bed it down..? 正如我之前提到的,在文档中,他们说在HQL中而不是在映射中指定获取模式是“通常的”,我认为这可能意味着HQL方式有更多的人流量来控制它。 。?

(by the way I added an extra 'name' field to A and B otherwise hibernate optimizes the retrieve because it can get all of B just from the foreign key on A) (顺便说一下,我给A和B添加了一个额外的'name'字段,否则hibernate优化了检索,因为它可以从A上的外键获得所有B)

As a distillation: 作为蒸馏:

@Fetch(JOIN) will be ignored if you use the Query interface (eg: session.createQuery()) but it will be properly used if you use the Criteria interface. 如果使用Query接口(例如:session.createQuery()),将忽略@Fetch(JOIN),但如果使用Criteria接口,它将被正确使用。

This is practically a bug in Hibernate which was never resolved. 这实际上是Hibernate中的一个从未解决的错误。 It is unfortunate because a lot of applications use the Query interface and cannot be migrated easily to the Criteria interface. 很不幸,因为许多应用程序使用Query接口,无法轻松迁移到Criteria接口。

If you use the Query interface you always have to add JOIN FETCH statements into the HQL manually. 如果使用Query接口,则必须手动将JOIN FETCH语句添加到HQL中。

When I select Test2 from the db, I can see that a separate select is being made to get the details of the associated test3 class. 当我从db中选择Test2时,我可以看到正在进行单独的选择以获取相关test3类的详细信息。

I'm very interested by the code of the other answer because that's what I'm seeing too when testing the code you're showing, it generates two selects for a from Test2 . 我对其他答案的代码非常感兴趣,因为这也是我在测试你正在展示的代码时所看到的,它为from Test2生成两个选择。

I'm using the following dependencies: 我正在使用以下依赖项:

  • org.hibernate:hibernate-entitymanager:jar:3.4.0.GA:compile org.hibernate作为:休眠-的EntityManager:罐子:3.4.0.GA:编译
  • org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile org.hibernate作为:EJB3持久性:罐子:1.0.2.GA:编译
  • org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile org.hibernate作为:冬眠公地的注解:罐子:3.1.0.GA:编译
  • org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile org.hibernate作为:冬眠的注解:罐子:3.4.0.GA:编译
  • org.hibernate:hibernate-core:jar:3.3.0.SP1:compile org.hibernate作为:休眠核心:罐子:3.3.0.SP1:编译

I set the FetchType to EAGER out of desperation, even though it defaults to EAGER anyway for OneToOne mappings, but it made no difference. 我将FetchType设置为EAGER绝望,即使它无论如何都默认为EAGER OneToOne映射,但它没有任何区别。

This has no impact if you use Hibernate annotations because the Hibernate annotations overrides the EJB3 fetching options. 如果使用Hibernate注释,这没有任何影响,因为Hibernate注释会覆盖EJB3提取选项。 See 2.4.5.1. 2.4.5.1。 Lazy options and fetching modes . 懒惰选项和提取模式

I created a very simple application to test the scenario you are getting and your code should work (it is working for me). 我创建了一个非常简单的应用程序来测试你得到的场景,你的代码应该工作(它对我有用)。 The only thing I have tried that will give me multiple select statements is setting max_fetch_depth to 0. If set to 2 (or not configured) I get the left outer join in my query. 我尝试过的唯一能给我多个select语句的是将max_fetch_depth设置为0.如果设置为2(或未配置),我在查询中得到左外连接。 What version of hibernate are you using? 您使用的是什么版本的hibernate? I am using 3.4.0.GA. 我使用的是3.4.0.GA.

EDIT: Below is the simple application I used (with the same versions mentioned by Pascal): 编辑:下面是我使用的简单应用程序(与Pascal提到的相同版本):

cfg: 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>

Person entity -- kept it simple only have @OneToOne, adding JoinColumn, etc made no difference. 人物实体 - 保持简单只有@OneToOne,添加JoinColumn等没有区别。

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

Simple test: 简单测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM