hibernate - @ManyToOne(fetch = FetchType.LAZY) 不适用于非主键引用的列

标签 hibernate jpa

我在创建 @ManyToOne 关联以延迟加载时遇到了一些麻烦。我正在使用 fetch=LAZY 但是当主键列没有进行连接时它不起作用。
我知道这个问题已经是 asked但我认为它没有得到正确的回答,所以我提供了详细的信息来澄清这个问题。
这是我的模型:

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 方法是重复的,以尝试两种情况来加入实体。
案例一:通过 DummyA 主键映射 DummyB -> DummyA
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dummy_id")
这很好用,只执行一个查询来检索 DummyB 对象。
案例 2:通过 DummyA NON 主键(字段名)映射 DummyB -> DummyA
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dummy_name", referencedColumnName="name")
执行相同的 dummyB 选择,但紧接着,执行 dummyA 选择,按 name=?获取相关的 A 对象。
我正在使用一个非常简单的 jUnit 来执行过滤:
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:编译
  • 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:编译
  • org.hibernate:hibernate-validator:jar:4.3.2.Final:提供

  • 我已经尝试过的其他事情:
  • 添加hiberante的@LazyToOnegetDummyA()方法没有任何效果。
  • @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "dummya_name", referencedColumnName = "name")
    @LazyToOne(LazyToOneOption.PROXY)
    
  • 创建从 DummyB 表到 dummyA 的外键(以及 dummy.name 字段中的唯一约束)无效。
  • 添加 @Column(unique = true)DummyA getName()方法没有成功。
  • 设置 optional=truefalse根据建议 here也没有效果。
  • 尝试使用 setFetchMode 强制延迟加载在标准不起作用时, DummyA select 继续执行。
  • List lst = session.createCriteria(DummyB.class)
    .add(Restrictions.eq("id", idDummyB)).
    setFetchMode("dummyA", FetchMode.SELECT)
    .list();
    
    我在 Hibernate 的文档中找不到引用此行为的点,所以我想知道我的注释中是否有任何问题,或者我遇到了 Hibernate 错误。
    谁能告诉?
    由 md-dev 请求更新:
    为了更清楚地设置它:
    这是预期的行为还是错误?如果这是预期的行为,它记录在哪里?
    谢谢你。

    最佳答案

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

    绝对没有任何我能够测试/更改的东西以任何方式解释了这一点,我可以可靠地重现它。

    我必须在我的使用非 PK 连接的应用程序中实现的解决方案就是丢弃 @ManyToOne。/@OneToMany注释对和手动写入集合获取(使用 transient 变量缓存结果)。工作量更大,但性能要高得多,因为我的一些对象有 5 或 6 个 @ManyToOne对象和所有这些都被 Hibernate 通过单独的选择热切地获取。

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

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

    关于hibernate - @ManyToOne(fetch = FetchType.LAZY) 不适用于非主键引用的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30082281/

    相关文章:

    java - 即使添加了 Hibernate,它也没有被导入

    java - 使用 Spring CrudRepository 的 Hibernate LazyInitializationException

    java - 读取组件 tynamo/PropertyEditBlocks :palette_set 的参数 'selected' 失败

    java - @OneToMany 不创建连接表

    jpa - 从 Spring mvc Controller 方法更新 JPA 实体以及使用隐藏输入字段存储 ID 的问题

    java - 如何在@NamedEntityGraph 中仅加载子图中的指定属性

    java - Hibernate 具有相同类的多对多,无法编写 JSON : Infinite recursion

    java - 为什么这个@JsonIgnore 修复了我的无限循环?

    java - 是否可以从与 HQL 的多对多关联中批量删除?

    java - JPA级联不插入外键