【问题标题】:Query for Foreign Key string ID without fetching the actual entity在不获取实际实体的情况下查询外键字符串 ID
【发布时间】:2021-12-19 04:42:43
【问题描述】:

鉴于下面的模型,当使用 JPA 从myentity 表中获取实体时,是否有办法防止从anotherentity 表中获取实体的二次获取,但会为我们提供@987654323 @String 值(用作外键)本身?

据我所知,由于 Java 中声明的类型,这不可能,我想知道是否有办法访问该信息而无需额外的提取,考虑到它是 确实在myentity 表中作为实际的varchar 列。

如果有帮助,我们使用 EclipseLink 作为我们的 JPA 提供者。

当前型号

@Entity
@Table(name = "myentity")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@IdClass(MyIdClass.class)
public class MyEntity {

    @Id
    @Column(updatable = false)
    private String foo;

    @Id
    @Column(updatable = false)
    private String bar;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "my_foreign_key", referencedColumnName = "external_pk")
    private AnotherEntity anotherEntity;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class MyIdClass implements Serializable {

    private String foo;
    private String bar;
}
@Entity
@Table(name = "anotherentity")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class AnotherEntity {

    @Id
    @Column(name = "external_pk", nullable = false, updatable = false)
    private String externalPk;

    @Column
    private String something;
}

【问题讨论】:

  • 不,你不能。但是你可以定义 anotherEntity LAZY 然后用外键添加一个额外的属性

标签: java jpa spring-data-jpa eclipselink


【解决方案1】:

如果 oneToOne 关系不是可选的,您可以使用 optional = false, fetch = FetchType.LAZY 附加注释,如下所示:

@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "my_foreign_key", referencedColumnName = "external_pk")
private AnotherEntity anotherEntity;

然后您将能够使用myEntity.getAnotherEntity().getKey() 访问其密钥,而无需加载关系。 Here's a POC using hibernate

【讨论】:

  • 有趣。我将不得不审查你所链接的内容。我认为:1) 当涉及到*ToOne 关系时,Hibernate 并不关心FetchType.LAZY,而是继续加载它。 2) 如果实体还没有被急切地加载,那么通过 getter 访问它正是实际触发 fetch 的原因 (myEntity.getAnotherEntity())。
  • 1) Hibernate 必须知道它是否应该使用 null 或代理类初始化 anotherEntity。通过告诉它optional=false,它假定它不为空并且不需要急切地获取关联(fetch = FetchType.LAZY 仍然是必需的,因为 EAGER 是默认值)。
  • 2) 非常违反直觉,但是检查 repo 中的测试,您可以在日志中看到 anotherEntity 永远不会被获取。您还可以看到 myEntity.getAnotherEntity().getSomething() 将抛出 LazyInitializarionException,因为未获取 AnotherEntity。
【解决方案2】:

如果您希望能够访问 my_foreign_key 外键值而不必调用 MyEntity.getAnotherEntity().getId() 并执行 anotherEntity 的完整获取,您可能应该将其映射为只读基本映射MyEntity 实例:

public class MyEntity {
...
    @Column(updatable = false)
    private String bar;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "my_foreign_key", referencedColumnName = "external_pk")
    private AnotherEntity anotherEntity;

    @Column(name = "my_foreign_key",updatable = false, insertable=false)
    private String myForeignKey;
}

作为一个额外的好处,虽然 EclipseLink 在这种类型的映射上做得很好,但它可以用于查询以防止无意中不必要地强制表连接。缺点是您必须自己从关系中设置此值以保持该值与关系值同步 - @MapsId 可能有效,但它适用于 ID 映射中涉及的关系,因此可能不可移植。

【讨论】:

  • 如果我选择read-only 列,那么我将无法更改OneToOne 关系以指向新实体,对吧?
  • 列定义为只读不会影响 OneToOne 映射。这只是意味着对此字符串所做的更改不会保留在该列中。当从数据库加载关系时,对关系所做的更改将显示在此字符串中,如果您更改其中一个,则应用程序应在内存中保持两者同步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
相关资源
最近更新 更多