当在事务上下文中使用equals()方法进行比较时,单端关联在Hibernate中被破坏
下面给出了国家与州之间的一对多关系(表名在数据库中采用当在事务上下文中使用equals()方法进行比较时,单端关联在Hibernate中被破坏,hibernate,jpa,lazy-loading,equals,many-to-one,Hibernate,Jpa,Lazy Loading,Equals,Many To One,下面给出了国家与州之间的一对多关系(表名在数据库中采用state\u table,因为在某些RDBMS中,状态可能是保留字) 下面给出了关联的反面(我假设不要求拥有方出现) 在equals()和hashcode()方法中,是Java 7中引入的一个实用程序类,只包含静态实用程序方法 下面的代码段使用上述实体类中的equals()方法作为示例 StateTable stateTable = entityManager.find(StateTable.class, 1L); Country coun
state\u table
,因为在某些RDBMS中,状态可能是保留字)
下面给出了关联的反面(我假设不要求拥有方出现)
在equals()
和hashcode()
方法中,是Java 7中引入的一个实用程序类,只包含静态实用程序方法
下面的代码段使用上述实体类中的equals()
方法作为示例
StateTable stateTable = entityManager.find(StateTable.class, 1L);
Country country = entityManager.find(Country.class, 1L);
stateTable.getCountryId().hashCode();
System.out.println("countryId = " + stateTable.getCountry().getCountryId());
System.out.println("equals = " + country.equals(stateTable.getCountry()));
第一个stdout语句显示与实体主键(countryId
类型Long
)对应的正确值1
然而,第二个stdout语句返回false
,尽管在获取时两个对象中的countryId
(主键)应该是相同的,但返回的结果令人难以置信——它已被破坏
实体类中equals()
方法中的这两个stdout语句输出以下内容
entity=false中的equals()
this.countryId=1:other.countryId=null
尽管所提供的country对象不是null
,如equals()
中的第一条stdout语句所确认,((国家)obj)。countryId
意外地返回null
,因此,equals()
method始终返回false
而不管作为参数提供的对象是什么,因为object
equalsnull
从来都不是真的无论如何都不应该发生这种情况。
@ManyToOne
关联被延迟初始化(fetch=FetchType.LAZY
)。如果它转到fetch=FetchType.EGAR
,那么一切都会正常进行。equals()
方法根据提供的对象返回正确的结果
代码在Spring服务中的事务下执行,该事务由以下注释标记
@Service
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
因此,不应该存在初始化惰性关联的问题。JPA中明确规定了这一点
对于收集关系,发送size()
通常是最好的方式
以确保实例化惰性关系适用于OneTONE和
多通关系,通常仅访问关系是
足够了(即employee.getAddress()
),尽管对于一些JPA提供商来说是这样
如果使用代理,则可能需要向对象发送消息
(即employee.getAddress().hashCode()
)
最后一条语句表示特定于提供者的行为
尽管对于一些使用代理的JPA提供商,您可能需要发送
对象包含一条消息(即employee.getAddress().hashCode()
)
然而,我完成了两种方法的尝试,但都没有用
stateTable.getCountry()
的值赋值给另一个变量,然后将其传递给equals()
)。就是
Country anotherCountry = stateTable.getCountry();
country.equals(anotherCountry); // Always returns false same as mentioned above.
hashcode()
,以确保在调用equals()
并通过country对象之前,惰性关联在事务上下文中初始化冬眠有什么问题?解决方案是什么?不要直接访问字段。而是在
equals
方法中使用getter。不要直接访问字段。相反,在equals
方法中使用getter。您必须了解代理是如何工作的。代理从实际类派生,但不保存其数据。从数据库加载代理时,将创建该类的另一个实例(本例中为Country),这是一个普通实例。它保存数据。代理将所有调用转发到此实例
您的代码有两个潜在问题
- 字段不应由另一个对象访问,因为它可能是代理。代理字段未初始化。调用getter,就可以得到值
返回代理类型,而不是实际类型。不一定是.class
。如果(!(Cat的其他实例))返回false,则使用国家
请注意,由于代理将所有调用转发给真实对象,因此在您的实体中,this永远不会引用代理。但是你得到的每一个参数都可能是一个代理。你必须了解代理是如何工作的。代理从实际类派生,但不保存其数据。从数据库加载代理时,将创建该类的另一个实例(本例中为Country),这是一个普通实例。它保存数据。代理将所有调用转发到此实例 您的代码有两个潜在问题
- 字段不应由另一个对象访问,因为它可能是代理。代理字段未初始化。调用getter,就可以得到值
返回代理类型,而不是实际类型。不一定是.class
。如果(!(Cat的其他实例))返回false,则使用国家
请注意,由于代理将所有调用转发给真实对象,因此在您的实体中,this永远不会引用代理。但是您得到的每个参数都可能是一个代理。此博客条目应该有帮助此博客条目应该有帮助您是否总是在项目中的每个实体中使用业务密钥、代理密钥或
equals()
和hashcode()
中的其他内容来避免自动生成字段
Country anotherCountry = stateTable.getCountry();
country.equals(anotherCountry); // Always returns false same as mentioned above.