使用来自Hibernate实体管理器的find和createQuery的不同SQL [英] Different SQL using find and createQuery from Hibernate entity manager

查看:105
本文介绍了使用来自Hibernate实体管理器的find和createQuery的不同SQL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Hibernate 3.3.0.GA,我注意到一些奇怪的行为,没有记录(我认为).

I'm using Hibernate 3.3.0.GA and I noticed some strange behavior, not documented (I think).

我注意到entityManager.find解决了我实体的EAGER关系,而entityManager.createQuery无法解决.

I noticed that entityManager.find resolve the EAGER relationships of my entity and entityManager.createQuery not.

例如,如果我有一个实体:

Per example, if I have an entity:

@Entity
public class Person {

     @Id
     private int id;

     private String name;

     @ManyToOne //EAGER by default in JPA
     private Address address;

}

使用entityManager.find(Person.class, 1L)生成的SQL:

select
    person0_.id as id1_1_,
    person0_.address_id as address3_1_1_,
    person0_.name as name1_1_,
    address1_.id as id2_0_ 
from
    Person person0_ 
left outer join
    Address address1_ 
        on person0_.address_id=address1_.id 
where
    person0_.id=?

以及使用entityManager.createQuery("SELECT p FROM Person where id = 1")生成的SQL:

And the generated SQL with entityManager.createQuery("SELECT p FROM Person where id = 1"):

select
    person0_.id as id1_,
    person0_.address_id as address3_1_,
    person0_.name as name1_ 
from
    Person person0_ 
where
    person0_.id=?

那么,有没有关于为什么发生这种情况的解释?对我来说,两者都必须具有相同的行为.

So, is there a explanation about why this happen? For me, both need to have the same behavior.

工作示例

我使用Hibernate 4.1.6.Final在我的存储库中创建了一个显示该问题的示例:

I create an example in my repository showing that problem, using Hibernate 4.1.6.Final: https://github.com/dherik/hibernate-find-em-so-question. Just use mvn clean install and the console will print the queries.

已更新

@KlausGroenbaek表示EclipseLink 2.5.2在两种方法中具有相同的行为.他也做了一个Hibernate示例,并且在两种方法中都获得了相似的结果(find进行联接提取,createQuery进行多次选择,都定义为EAGER).

@KlausGroenbaek said the EclipseLink 2.5.2 have the same behaviour in the two methods. He did a Hibernate example too and obtain the similar result in the two methods (find it does a join fetch and createQuery it does multiple selects, both EAGER by definition).

推荐答案

我查看了您的示例,并对其进行了修复,其工作原理与HiberNate 5.2.5 find()使用联接而createQuery使用多个选择一样.

I have looked at your example and after fixing it, it works exactly like HiberNate 5.2.5 find() uses a join and createQuery uses multiple selects.

在您的示例中未看到此信息的原因是因为您在数据库中没有 NO DATA ,find仍然进行了联接,但是由于数据库中没有Person,因此它没有.不需要查找任何地址,因此第二个选择丢失了.

The reason you don't see this in your example is because you have NO DATA in the database, find still does a join, but because there is no Person in the DB, it doesn't need to look for any Address, so the second select is missing.

但是,您会注意到,即使将数据添加到示例中,从地址中选择也不会显示.这是因为从使用find()以来,该地址已经在持久性上下文中,因此无需再次加载它-实际上,如果发生以下情况,JPA 必须返回与该地址完全相同的Java实例它已经被加载到持久化上下文中.如果您插入em.clear()或使用其他持久性上下文(EntityManager),则会看到选择内容,因为该地址尚未加载.

However, you will notice that even if you add data to your example, the select from address does not show up. This is because the address is already in the Persistence Context from when you used find(), so there is no need to load it again - In fact JPA MUST return the exact same Java instance for the address if it is already loaded in the Persistence Context. If you insert em.clear() or use a different Persistence Context (EntityManager) you will see the select because the address is not already loaded.

您的示例只是一个示例,但是绝对禁止在字段中存储由应用程序管理的EntityManager的方式,当您自己管理自己时,它们应该始终是局部变量.如果您使用容器管理的EntityManager(Spring JavaEE),则在使用@PersistenceContext进行注入时,它们可以是字段,但这仅是因为注入的EntityManager是存储状态的代理,其状态为ThreadLocal.

Your example is of cause just an example, but the way you store an application managed EntityManager in a field, is absolutely forbidden, they should always be local variables when you manage them your self. If you use a container managed EntityManager (Spring JavaEE) they can be fields when injected using @PersistenceContext, but that is only because the injected EntityManager is a proxy which stores the state is a ThreadLocal.

自2009年以来,我广泛使用了JPA,一开始我犯了很多错误,因为我不完全了解持久性上下文是什么,因此我有重叠的EntityManagers,未维护的双向关系,并且我没有完全了解实体状态,或了解容器还是应用程序管理的EntityManager.我从中学到了很多困难的方法(对我来说,这是调试和阅读EclipseLink源代码).回顾过去,我绝对应该买一本书以获取全局,而不是通过随机搜索我所遇到的问题来解决问题.对于没有读过JPA文档,一本好书或一篇专业文章的人,请帮自己一个忙,并从我的错误中学习.

I have used JPA extensively since 2009, and I made a lot of mistakes in the beginning because I didn't understand exactly what a Persistence Context was, so I had overlapping EntityManagers, unmaintained bidirectional relations, and I didn't fully understand Entity states, or container vs application managed EntityManager. Much of it I learned the hard way (which for me was debugging and reading the EclipseLink source code); looking back I should definitely have bought a book to get the big picture, instead of solving problems by randomly Googling what I though the issue was. For anyone how have not read the JPA documentation, a good book, or in dept article, do your self a favor and learn from my mistakes.

这篇关于使用来自Hibernate实体管理器的find和createQuery的不同SQL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆