对于JPA实体中的if(coin_change >= .00)
{
coins += 1;
pennies += 1;
coin_change = coin_change - .01;
continue;
}
else
{
break;
}
关系,我只对实际的id引用感兴趣,而不是获取与该关系关联的整个模型。
例如,这些Kotlin JPA实体:
@ManyToOne
现在,当我从Kotlin代码访问@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
。
这太过分了,因为我只对Continent
感兴趣。
我尝试添加Continent.id
,例如:
@Access(AccessType.PROPERTY)
但是没有什么区别。整个@Entity
class Continent(
@Id
@Access(AccessType.PROPERTY)
var id: String,
仍从数据库中查询。
我尝试了Continent
,就像其他帖子(例如Hibernate one-to-one: getId() without fetching entire object)中提到的那样,但是我已经注意到对此的反馈意见不一。
我将Kotlin @Access(AccessType.PROPERTY)
与Hibernate 5.3.7.Final
一起使用。
我想知道{em> 1) 1.3.0
方法是否正确, 2)是否也可以与Kotlin一起使用?也许Kotlin生成Java代码的方式引起了问题?
更新
我创建了一个简单的测试项目,证明正在查询该大陆。 https://github.com/marceloverdijk/hibernate-proxy-id
该项目包含一个简单的测试,用于检索@Access(AccessType.PROPERTY)
并已启用SQL日志记录。从记录中可以看到查询了大陆 。
更新2
答案 0 :(得分:1)
此行为由JPA规范定义,该规范要求在访问任何属性(甚至是标识符)时都要提取关联。
传统上,Hibernate在访问其标识符时不会初始化实体代理,但是此行为与JPA规范不一致,因此需要显式禁用此JPA合规性策略。
实际上,我在Hibernate ORM中创建了这两个测试用例,并且一切正常:
默认情况下,仅访问ID时,代理不会初始化。
这是测试:
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
实体添加了compare
或Continent
实现。
答案 1 :(得分:1)
我有类似的问题。原来所有@Entity注释的类都必须是“打开的”。否则,Hibernate将无法创建代理子类,因此将无法延迟加载您的实体。
答案 2 :(得分:1)
正如Adrien Dos Reis提到的那样,Hibernate要求所有带有@Entity
注释的类都必须是开放的(即,不是final
)。不必手动打开类和属性来进行所有繁琐的工作,只需将all-open
插件添加到kotlin-maven-plugin
即可,如下所示:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>all-open</plugin>
<plugin>jpa</plugin>
</compilerPlugins>
<pluginOptions>
<option>all-open:annotation=javax.persistence.Entity</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
请注意,选项all-open:annotation=javax.persistence.Entity
已添加到全打开插件中。这将导致所有带@Entity注释的类在默认情况下处于打开状态。有关详细信息,请参阅https://kotlinlang.org/docs/reference/compiler-plugins.html#all-open-compiler-plugin