java - JPA 引用 : are there any guarantees related to field contents?

标签 java hibernate jpa

JPA 的 EntityManager#getReference() 返回一些非常惰性的东西,通常是代理。仅当访问属性时,它才会访问数据库。根据文档:

Get an instance, whose state may be lazily fetched

我想知道的是研究此类代理的字段是否有意义。

我有以下两个形成一对多关系的类:

@Entity
@Table(name = "parent")
public class Parent {
    @Id
    @GeneratedValue
    public UUID id;
    public String name;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    public List<Child> children = new ArrayList<>();

    public void addChild(Child child) {
        children.add(child);
        child.parent = this;
    }

    public String getName() {
        return name;
    }

    public List<Child> getChildren() {
        return children;
    }
}

@Entity
@Table(name = "child")
public class Child {
    @Id
    @GeneratedValue
    public UUID id;
    public String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    public Parent parent;
}

请注意,这两个类都使用字段访问策略(因为 @Id 位于字段上,而不是 getter 上)。

在测试装置设置过程中,我通过 JDBC 将一个带有两个子项的 Parent 添加到数据库,以避免 Parent 实例在 EntityManager 中缓存。我没有展示这段代码,因为它庞大且简单。如果需要的话我可以稍后添加。

然后,我运行以下测试:

@Test
@Transactional
public void testWithFind() {
    Parent parent = entityManager.find(Parent.class, parentId);

    assertThat(parent.name, is("Joe"));
    assertThat(parent.children, hasSize(2));
}

@Test
@Transactional
public void testWithGetReference() {
    Parent parent = entityManager.getReference(Parent.class, parentId);

    assertNull(parent.name);
    assertThat(parent.children, hasSize(0));

    assertThat(parent.getName(), is("Joe"));
    assertThat(parent.getChildren(), hasSize(2));

    // ... but still ...
    assertNull(parent.name);
    assertThat(parent.children, hasSize(0));
}

两次测试均成功。

我可以在控制台中看到JPA实际上查询了数据库。对于 find() 相关测试,它是

Hibernate: select parent0_.id as id1_2_0_, parent0_.name as name2_2_0_ from parent parent0_ where parent0_.id=?
Hibernate: select children0_.parent_id as parent_i3_0_0_, children0_.id as id1_0_0_, children0_.id as id1_0_1_, children0_.name as name2_0_1_, children0_.parent_id as parent_i3_0_1_ from child children0_ where children0_.parent_id=?

对于 getReference() 来说是

Hibernate: select parent0_.id as id1_2_0_, parent0_.name as name2_2_0_ from parent parent0_ where parent0_.id=?
Hibernate: select children0_.parent_id as parent_i3_0_0_, children0_.id as id1_0_0_, children0_.id as id1_0_1_, children0_.name as name2_0_1_, children0_.parent_id as parent_i3_0_1_ from child children0_ where children0_.parent_id=?

可以看出,find() 填充了 String 和集合字段。但对于 getReference() 返回的“实体”来说,情况并非如此:即使在调用 getter 之后,字段仍保持其初始状态。

我知道使用代理(或者可能是任何其他“合法”机制)不可能拦截字段访问,因此代理主要在 getters 级别工作。但是实体被注释为使用字段访问策略,因此用户显然期望字段将用于获取值,而不是 getter。我在规范中没有找到任何说明,并且没有提及此类代理的“仅 getter”语义(或者我只是没有找到此类提及)。

我的问题是:

  1. 这是 JPA 规范的差异,还是我没有正确理解它?

  2. 是否可以使用字段来访问 getReference() 返回的实体的组件,否则没有任何意义?

我使用 Hibernate 5.3.9 作为 JPA 提供程序。

最佳答案

根据 JPA 规范,不允许使用对字段的公共(public)访问:

2.2 Persistent Fields and Properties

The persistent state of an entity is accessed by the persistence provider runtime[1] either via JavaBeans style property accessors (“property access”) or via instance variables (“field access”). Whether persistent properties or persistent fields or a combination of the two is used for the provider’s access to a given class or entity hierarchy is determined as described in Section 2.3, “Access Type”.

Terminology Note: The persistent fields and properties of an entity class are generically referred to in this document as the “attributes” of the class.

The instance variables of a class must be private, protected, or package visibility independent of whether field access or property access is used. When property access is used, the property accessor methods must be public or protected.

It is required that the entity class follow the method signature conventions for JavaBeans read/write properties (as defined by the JavaBeans Introspector class) for persistent properties when property access is used.

In this case, for every persistent property property of type T of the entity, there is a getter method, getProperty, and setter method setProperty. For boolean properties, isProperty may be used as an alternative name for the getter method.

关于java - JPA 引用 : are there any guarantees related to field contents?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56442380/

相关文章:

java - 使用 GWT 进行图像平移和缩放

java - 在 JSON 填充的 Android View 中单击的复选框列表

java - JQuery Ajax POST 方法不起作用? $.post

java - 将项目升级到grails 2.0.1

mysql - (mySQL 数据库 - 存储不同类型的相同值

java - 找不到符号方法 getSupportFragmentManager()

mysql - serverError :class javax. faces.el.E​​valuationException 无法执行查询

hibernate - 如何动态设置 JPA 标准查询的位置/命名参数?

mysql - 我无法在阔叶中使用 em.merge 存储实体

jpa - OpenJPA 上的列顺序