java Hibernate noob fetch join 问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2931936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate noob fetch join problem
提问by Jeremy
I have two classes, Test2 and Test3. Test2 has an attribute test3 that is an instance of Test3. In other words, I have a unidirectional OneToOne association, with test2 having a reference to test3.
我有两个类,Test2 和 Test3。Test2 有一个属性 test3,它是 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. This is the famous 1+N selects problem.
当我从数据库中选择 Test2 时,我可以看到正在进行一个单独的选择来获取关联的 test3 类的详细信息。这就是著名的 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. Here are the relevant portions of my setup..
但是,将 fetch 设置为 join 后,我仍然会看到单独的选择。这是我的设置的相关部分..
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.
注意,出于绝望,我将 FetchType 设置为 EAGER,即使对于 OneToOne 映射它默认为 EAGER,但它没有任何区别。
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? 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"
编辑:我几乎已经放弃尝试使用 FetchMode.JOIN - 任何人都可以确认他们已经让它工作,即产生一个左外连接?在文档中,我看到“通常,映射文档不用于自定义提取。相反,我们保留默认行为,并针对特定事务覆盖它,在 HQL 中使用左连接提取”
If I do a left join fetch instead:
如果我执行左连接获取:
query = session.createQuery("from Test2 t2 left join fetch t2.test3");
query = session.createQuery("from 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. 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.
我已经学到的一件事 - 我在旧版本的 hibernate 上运行,因为我没有意识到 maven 存储库已经过时了。现在我也连接到 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:
如果我按照 Ross 的方式做事,加载时会创建一个左外连接。如果我使用列表进行操作,则会发出单独的选择。这是相关的代码。只有改变这一点才能重现行为上的差异:
/* 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'. 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 添加了一个额外的“名称”字段,否则休眠会优化检索,因为它可以仅从 A 上的外键获取所有 B)
采纳答案by Pascal Thivent
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.
当我从数据库中选择 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:ejb3-persistence:jar:1.0.2.GA:compile
- org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile
- org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
- org.hibernate:hibernate-core:jar:3.3.0.SP1:compile
- org.hibernate:hibernate-entitymanager:jar:3.4.0.GA:compile
- org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile
- org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile
- org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
- org.hibernate:hibernate-core:jar:3.3.0.SP1:compile
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,即使对于 OneToOne 映射它默认为 EAGER,但它没有任何区别。
This has no impact if you use Hibernate annotations because the Hibernate annotations overrides the EJB3 fetching options. See 2.4.5.1. Lazy options and fetching modes.
如果您使用 Hibernate 注释,这没有影响,因为 Hibernate 注释覆盖 EJB3 获取选项。见2.4.5.1。懒惰的选项和获取模式。
回答by sola
As a distillation:
作为蒸馏:
@Fetch(JOIN) will be ignored if you use the Query interface (e.g.: 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. It is unfortunate because a lot of applications use the Query interface and cannot be migrated easily to the Criteria interface.
这实际上是 Hibernate 中从未解决的错误。很遗憾,因为很多应用程序都使用Query 接口,无法轻松迁移到Criteria 接口。
If you use the Query interface you always have to add JOIN FETCH statements into the HQL manually.
如果您使用 Query 接口,您总是必须手动将 JOIN FETCH 语句添加到 HQL 中。
回答by Ross
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. What version of hibernate are you using? I am using 3.4.0.GA.
我创建了一个非常简单的应用程序来测试您获得的场景并且您的代码应该可以工作(它对我有用)。我唯一尝试过的会给我多个选择语句的方法是将 max_fetch_depth 设置为 0。如果设置为 2(或未配置),我会在查询中获得左外连接。您使用的是什么版本的休眠?我正在使用 3.4.0.GA。
EDIT: Below is the simple application I used (with the same versions mentioned by Pascal):
编辑:下面是我使用的简单应用程序(与 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>
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

