仅需要实体 ID 时如何避免初始化 Hibernate 代理

2023-12-14

For a @ManyToOneJPA 实体中的关系 我只对实际的 id 引用感兴趣,而不是获取与该关系关联的整个模型。

以这些 Kotlin JPA 实体为例:

@Entity
class Continent(
        @Id
        var id: String,
        var code: String,
        var name: String
) : Comparable<Continent> {

    companion object {
        private val COMPARATOR = compareBy<Continent> { it.id }
    }

    override fun compareTo(other: Continent): Int {
        return COMPARATOR.compare(this, other)
    }
}

@Entity
class Country(
        @Id
        var id: String,
        var alpha2Code: String,
        var alpha3Code: String,
        var name: String,
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "continent_id")
        var continent: Continent

) : Comparable<Country> {

    companion object {
        private val COMPARATOR = compareBy<Country> { it.id }
    }

    override fun compareTo(other: Country): Int {
        return COMPARATOR.compare(this, other)
    }
}

现在当我访问country.continent.id从我的 Kotlin 代码中可以看到完整的Continent实际上是从数据库中查询出来的。 这太过分了,因为我只对Continent.id.

我尝试过添加@Access(AccessType.PROPERTY) like:

@Entity
class Continent(
        @Id
        @Access(AccessType.PROPERTY)
        var id: String,

但这没有什么区别。整体Continent仍然从数据库中查询。

我尝试过@Access(AccessType.PROPERTY)正如其他帖子中提到的那样(例如Hibernate 一对一: getId() 而不获取整个对象),但我已经注意到对此的反馈意见不一。

我正在使用休眠5.3.7.Final与科特林1.3.0.

我怀疑是否1) the @Access(AccessType.PROPERTY)方法是正确的并且2)这也应该与 Kotlin 一起使用吗?也许 Kotlin 生成 Java 代码的方式导致了问题?

UPDATE

我创建了一个简单的测试项目,证明该大陆正在被查询。https://github.com/marceloverdijk/hibernate-proxy-id

该项目包含一个简单的测试检索country.continent.id并且 SQL 日志记录已启用。从伐木可以看到大陆is询问。

UPDATE 2

我已经创建了https://youtrack.jetbrains.net/issue/KT-28525为了这。


此行为由 JPA 规范定义,该规范要求在访问任何属性(甚至标识符)时获取关联。

传统上,Hibernate 在访问其标识符时不会初始化实体代理,但这种行为与 JPA 规范不一致,因此需要显式禁用此 JPA 合规性策略。

事实上,我在 Hibernate ORM 中创建了这两个测试用例,一切都按预期工作:

  • ManyToOneLazyLoadingByIdJpaComplianceTest
  • ManyToOneLazyLoadingByIdTest

默认情况下,仅访问id时,Proxy不会初始化。

这是测试:

Continent continent = doInJPA( this::entityManagerFactory, entityManager -> {
    Country country = entityManager.find( Country.class, 1L );

    country.getContinent().getId();

    return country.getContinent();
} );

assertEquals( 1L, (long) continent.getId());

assertProxyState( continent );

默认情况下,这是预期的行为:

protected void assertProxyState(Continent continent) {
    try {
        continent.getName();

        fail( "Should throw LazyInitializationException!" );
    }
    catch (LazyInitializationException expected) {

    }
}

但是,如果我们切换到 JPA 兼容性 moe:

<property name="hibernate.jpa.compliance.proxy" value="false"/>

这就是我们得到的:

protected void assertProxyState(Continent continent) {
    assertEquals( "Europe", continent.getName() );
}

因此,一切都按预期进行。

问题来自 Kotlin 或 Spring Data JPA。您需要进一步调查它并了解代理为何被初始化。

最有可能的是因为toString or compare实施添加到Continent entity.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅需要实体 ID 时如何避免初始化 Hibernate 代理 的相关文章

随机推荐

  • 模式扩展以运行命令

    知道我能跑echo or mv扩展这样的模式 echo 0 9 A Z 我很想知道是否有办法执行相同的操作但运行命令 docker compose stop rm up d 上面的例子不起作用 但有某种方法可以实现这一点 分别运行 stop
  • 如何实现错误处理?

    我的 AutoIt 脚本生成了一个我想要处理的错误 将任何错误发送到自定义函数的方式也可以 在VBA中我使用OnErrorGoTo 但我无法在 AutoIt 中找到类似的东西 我的代码 Func Start While 1 If Proce
  • Apps 脚本 - 在 Google 表格上复制“将图像放入所选单元格”

    我目前正在通过 Apps 脚本功能在 Google 表格中插入多个图像插入图片 使用它 该函数将图像插入到单元格上方 而不是单元格内部 我可以通过单击三个点按钮 然后选择 将图像放入所选单元格 将该图像插入到单元格中 如下所示link 这里
  • 没有 Google Play 的 Android Admob

    我在网上找不到任何东西 有没有办法使用 AdMob SDK 通过我的应用程序获利 而无需将应用程序放在 Google Play 商店中 你们中有人可能知道吗 提前致谢 您无需通过 Google Play 分发应用程序即可使用 AdMob S
  • 嵌套查询 MVC LINQ

    我是新来的MVC and LINQ 目前 我在该项目上遇到了困难 并决定发布 My MVC View我想要实现的目标 Cut 1 20 2 40 Color 3 30 4 50 Perm 5 10 这是我的数据表的一些示例 ID Offer
  • 未捕获的类型错误未定义不是函数

    我是 JQuery 新手 不知道如何处理诸如未捕获之类的错误TypeError undefined is not a function 我不知道如何按顺序排列下面的 jQuery 代码 有人可以安排一下吗 model Mvc4 WebGri
  • 有没有办法从 Zend Framework 的引导程序重定向浏览器?

    我需要根据引导文件中的某些条件进行重定向 这是在定义前端控制器和路由之后完成的 我怎么做 我知道我可以简单地使用 header Location 重点是我需要使用 Router 来构建 URL 一年多后 我在 ZF 编程 我为你的问题找到了
  • 如何导航到 WP7 中的不同枢轴项目

    我有一个全景页面 其中有 3 个按钮 我已将一个数据透视页添加到具有 3 个数据透视项的同一项目中 当我单击全景页面中的按钮 1 时 它应该转到数据透视页面中的第一个数据透视项目 当我单击全景页面中的按钮 2 时 它应该转到数据透视页面中的
  • Boost asio - 分离不同的数据块

    想象一下 我们创建简单的客户端 服务器应用程序来将文件从客户端发送到服务器 我们使用boost asio 服务器开始监听 客户端连接到服务器 客户端发送文件名和文件内容 但服务器只接收字节流 服务器如何检测文件名结尾和文件内容开头 我的第一
  • 使用 appium 运行量角器脚本时:使用定位器找不到元素

    我正在使用 Ipad Air 模拟器 appium 和量角器来自动执行 Angular JS 站点的测试 但测试无法成功通过 它告诉我使用定位器找不到元素 我确信 xpath 与 Appium 生成的相同 这是我的配置文件 exports
  • Java JNDI API 用户无法通过多林设置对 AD 进行身份验证

    在我的测试环境中 我设置了两个活动目录林 A 和 B 每个林都有一个域控制器 并且林有两种信任设置 我有用户 森林中的用户 S 和森林中的用户 B 我已经使用 adfind exe 来测试 userA 和 userB 是否可以通过点击for
  • 如何始终在 MSBuild 中执行目标

    我有一个 MSBuild 文件 它在编译应用程序之前操作 AssemblyInfo 文件 在构建结束时 它会恢复 AssemblyInfo 文件 它通过备份文件 操作文件 然后在构建时间后恢复文件来实现此目的 除非在构建过程中发生错误 否则
  • ASP.NET 数据缓存 - 在应用程序域重新启动后保留内容

    我正在使用 ASP NET 的数据缓存 API 例如 HttpRuntime Cache Insert my data my key 有没有办法配置缓存 以便在应用程序域回收时保留其内容 我将许多对象加载到缓存中 但是每次应用程序域重新启动
  • PowerShell - 如何迭代 PSCustomObject 嵌套对象?

    我觉得这很简单 但我只是不明白 我不确定我的解释是否很好 我有下面的 JSON 文件 我想在 New 对象下获取 每个应用程序 App1 App2 App3 在下面的脚本行中 我本质上是尝试用一些变量替换 TestApp2 我想我正在尝试在
  • 删除第二个冒号后的文本

    我需要删除第二个冒号之后的所有内容 我有几种日期格式 需要使用相同的算法进行清理 a lt 2016 12 31T18 31 34Z b lt 2016 12 31T18 31Z 我尝试匹配两个列组 但我似乎无法找出如何删除第二个匹配组 s
  • Python简单数字比较

    问题 计算机随机生成一个数字 用户输入一个数字 计算机会告诉你是否太高或太低 然后你将继续猜测 直到猜出数字为止 我的解决方案 import random computer random randint 1 500 def guessNum
  • Robotium:请安装兼容的 Android API 级别(15 或更高)

    尝试运行新的 Robotium 测试时出现此错误 有谁知道如何修理它 我拥有所需的所有 API 15 以及许多更高的 API 我缺少什么 这是我的 gradle 文件的一部分 android compileSdkVersion 25 bui
  • 将查询合并为一个

    我有以下疑问 Query 1 SELECT so ClientID All Channels as CustomerGroup so StatementID so Brand so Product Sum so Amount Amount
  • WaitHandle.WaitAny 匹配 WaitForMultipleObjects 功能

    我正在移植C API代码到 NET并研究函数调用WaitHandle WaitAny作为替代品WaitForMultipleObjects但是当调试时 NET4我可以看到这个函数被挂接到 private static extern int
  • 仅需要实体 ID 时如何避免初始化 Hibernate 代理

    For a ManyToOneJPA 实体中的关系 我只对实际的 id 引用感兴趣 而不是获取与该关系关联的整个模型 以这些 Kotlin JPA 实体为例 Entity class Continent Id var id String v