@ManyToOne(fetch = FetchType.LAZY)在非主键引用列上不起作用 [英] @ManyToOne(fetch = FetchType.LAZY) doesn't work on non-primary key referenced column

查看:223
本文介绍了@ManyToOne(fetch = FetchType.LAZY)在非主键引用列上不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在创建@ManyToOne关联时遇到了一些麻烦.我使用的是fetch = LAZY,但是当主键列未建立连接时,它将不起作用.

I'm having some troubles to make a @ManyToOne association to be loaded lazilly. I'm using the fetch=LAZY but it doesn't work when join isn't made by the primary key column.

我知道这个问题已经,但我认为此问题未得到正确回答,因此,我提供了详细的信息来澄清问题.

I know this question was already asked but I think it wasn't properly answered, so I provide detailed information to clarify the issue.

这是我的模特

DummyB -> DummyA

这些是表格:

create table dummyA  (
  id number(18,0), --pk
  name varchar2(20) -- unique field
);

create table dummyB  (
  id number(18,0),
  dummya_id number(18,0),
  dummya_name varchar2(20)
);

这些是实体:

@Entity
public class DummyA implements Serializable {

    private Long id;
    private String name;

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

}

@Entity
public class DummyB implements Serializable {

    private Long id;
    private DummyA dummyA;

    @Id
    public Long getId() {
        return id;
    }

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

    /* Case 1: mapping DummyB -> DummyA by DummyA NON primary key (field name) */
    // @ManyToOne(fetch = FetchType.LAZY)
    // @JoinColumn(name = "dummya_id")
    // public DummyA getDummyA() {
    // return dummyA;
    // }

    /* Case 2: mapping DummyB -> DummyA by DummyA primary key */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dummya_name", referencedColumnName = "name")
    @LazyToOne(LazyToOneOption.PROXY)
    public DummyA getDummyA() {
        return dummyA;
    }

    public void setDummyA(DummyA dummyA) {
        this.dummyA = dummyA;
    }

}

请注意,实体DummyB中的getDummyA方法是重复的,以尝试两种情况来加入实体.

Note getDummyA method in entity DummyB is duplicate to try out two cases to join the entities.

案例1:通过DummyA主键映射DummyB-> DummyA

@ManyToOne(获取= FetchType.LAZY) @JoinColumn(name ="dummya_id")

@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "dummya_id")

这很好用,只需执行一个查询即可检索DummyB对象.

This works fine, just one query is executed to retrieve DummyB objects.

案例2:通过DummyA NON主键(字段名称)映射DummyB-> DummyA

@ManyToOne(获取= FetchType.LAZY) @JoinColumn(name ="dummya_name",referencedColumnName ="name")

@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "dummya_name", referencedColumnName="name")

执行了相同的dummyB select,但是紧接着执行了一个用name =?过滤的dummyA select.来获取相关的A对象.

Same dummyB select is execute, but right after, a dummyA select is executed filtering by name=? to fetch the related A object.

我正在使用一个非常简单的jUnit来执行过滤:

I'm using a really simple jUnit to execute filtering:

public class DummyTest {

    @Autowired
    HibernateTransactionManager transactionManager;

    @Test
    @Transactional
    public void testFindDummyB() throws DAOException {
        Long idDummyB = 2L;

        Session session = getCurrentHibernateSession();

        List lst = session.createCriteria(DummyB.class)
                .add(Restrictions.eq("id", idDummyB)).list();

        assertTrue(lst.size() > 0);
    }

    private Session getCurrentHibernateSession() {
        return this.transactionManager.getSessionFactory().getCurrentSession();
    }

}

我的图书馆:

  • org.hibernate:hibernate-core:jar:4.2.17.Final:compile
  • org.hibernate.common:hibernate-commons-annotations:jar:4.0.2.Final:compile
  • org.hibernate.javax.persistence:hibernate-jpa-2.0-api:jar:1.0.1.Final:compile
  • org.hibernate:hibernate-validator:jar:4.3.2.Final:提供

我已经尝试过的其他方法:

Other things I've already tried:

  • 将hiberante的@LazyToOne添加到getDummyA()方法中没有任何作用.

  • Adding hiberante's @LazyToOne to getDummyA() method doesn't have any effect.

@LazyToOne(LazyToOneOption.PROXY) @ManyToOne(fetch = FetchType.LAZY,可选= true) @JoinColumn(name ="dummya_name",referencedColumnName ="name") @LazyToOne(LazyToOneOption.PROXY)

@LazyToOne(LazyToOneOption.PROXY) @ManyToOne(fetch = FetchType.LAZY, optional = true) @JoinColumn(name = "dummya_name", referencedColumnName = "name") @LazyToOne(LazyToOneOption.PROXY)

从DummyB表创建到dummyA的外键(以及dummya.name字段中的唯一约束)无效.

Creating a foreign key from DummyB table to dummyA (and an unique constraint in dummya.name field) has no effect.

尝试在条件中使用setFetchMode强制延迟加载不起作用,DummyA select继续执行.

Trying to force the lazy loading using the setFetchMode in the criteria didn't work, DummyA select keeps executing.

列表lst = session.createCriteria(DummyB.class).add(Restrictions.eq("id",idDummyB)). setFetchMode("dummyA",FetchMode.SELECT) .list() ;

List lst = session.createCriteria(DummyB.class) .add(Restrictions.eq("id", idDummyB)).setFetchMode("dummyA", FetchMode.SELECT) .list();

我在Hibernate的文档中找不到指向该行为的地方,所以我想知道我的注释中是否有任何错误,或者我遇到了Hibernate的错误.

I can't find in Hibernate's docs a point where it refers to this behaviour, so I wonder if there's anything is wrong in my annotations or I came upon a Hibernate bug.

谁能告诉?

由md-dev请求更新: 要使其更清晰:

这是预期的行为还是错误?如果这是预期的行为,它在哪里记录?

Is this the expected behaviour or is a bug? if this the expected behaviour, where is it documented?

谢谢.

推荐答案

看到与Hibernate 5.0.4完全相同的行为.如果连接列是主键,则@ManyToOne(带有互为OneToMany)和Lazy的提取将完美工作.如果不是,则延迟加载会中断,并且每次实例化对象时,Hibernate都会急切地获取所有ManyToOne.如果对1000条记录执行Criteria.list(),这可能会非常慢.最初是对1000条记录的单个查询,现在可以膨胀为5000条查询,以使用单个选择热切地获取各种@ManyToOne.

Seeing the exact same behaviour with Hibernate 5.0.4. @ManyToOne (with a reciprocal OneToMany) and Lazy fetching works perfectly if the join column is the primary key. If it's not, lazy loading breaks and Hibernate eagerly fetches all ManyToOne's every time an object is instantiated. This can be catastrophically slow if you do a Criteria.list() for, say, 1000 records. What started out as a single query for 1000 records can balloon into 5000 queries to eagerly fetch a variety of @ManyToOne's using individual selects.

绝对没有我能够测试/更改的内容以任何方式对此进行解释,并且我可以可靠地重现它.

Absolutely nothing I've been able to test/change has explained this in any way and I can reproduce it reliably.

我必须在使用非PK进行连接的应用程序中实现的解决方案是仅丢弃@ManyToOne/@OneToMany注释对,并手动编写集合提取操作(使用瞬态变量缓存结果).这样做的工作量更大,但考虑到我的一些对象有5或6个@ManyToOne对象,并且所有这些都由Hibernate急切地通过单个选择来获取,因此性能要高得多.

The solution I had to implement in my app that uses non-PK's for joins was to just trash @ManyToOne/@OneToMany annotation pairs and write collection fetches manually (caching the results with a transient variable). It's way more work but the performance is substantially higher given that some of my objects have 5 or 6 @ManyToOne objects and all of these were being eagerly fetched with individual selects by Hibernate.

不幸的是,我无法重新组织架构以适应Hibernate中的这个怪癖.我正在做一个涉及Heroku Connect的项目,当使用非主键的表中的"sfid"列完成来自Salesforce.com的数据合并时,表之间的联接.主键是Heroku Postgres数据库中记录唯一的一个单独值,不能用于进行联接,因为数据库中没有其他表引用此主键.

Unfortunately, I can't reorganize my schema to accommodate this quirk in Hibernate. I'm doing a project involving Heroku Connect and the joins between tables when merging data from Salesforce.com are done using a "sfid" column in the table that is not the primary key. The primary key is a separate value unique to the record in the Heroku Postgres database and can't be used to do joins on as no other tables in the database refer to this primary key.

我假设这是Hibernate中的错误;我所读或能够修改的任何内容都没有以任何方式影响此行为,并且正如我提到的,如果连接列是主键,我可以使系统完全按预期工作.

I'm assuming that this is a bug in Hibernate; nothing I've read or been able to modify has affected this behaviour in any way and, as I mentioned, I can make the system work exactly as expected if the join columns are the primary keys.

这篇关于@ManyToOne(fetch = FetchType.LAZY)在非主键引用列上不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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