Hibernate 5.3+ using hibernateLazyInitializer causes javax.persistence.EntityNotFoundException: Unable to find entity.Person

huangapple go评论80阅读模式
英文:

Hibernate 5.3+ using hibernateLazyInitializer causes javax.persistence.EntityNotFoundException: Unable to find entity.Person

问题

在升级 Hibernate 到 5.3+ 版本时,使用 getHibernateLazyInitializer().getIdentifier() 方法来获取 HibernateProxy 上的标识符时遇到了问题,这个 HibernateProxy 是由 Hibernate Envers 的 AuditedReader 加载的。

以下是您提供的代码示例:

@Entity
@Audited
public class Person {
    @Id
    private Long id;
    
    @Column(name="surname")
    private String name;

    @JoinColumn(name="country_id", foreignKey = @javax.persistence.ForeignKey(name="FK_country_id"))
    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    private Country country;
}

@Entity
@Audited
public class Country {
    @Id
    public Long id;

    @Column(name="countryName")
    public String countryName;
}

// 另一个类中的代码,我想从 Hibernate Envers 的 Person 表中获取 Country 的 ID
// field 是需要从对象中获取的变量的反射
// field = "country",需要从 personObject 中获取
private static Object getId(Object personObject, Field field) throws IllegalAccessException {
    Object countryObject = field.get(personObject);
    if (countryObject instanceof HibernateProxy) {
        return ((HibernateProxy)countryObject).getHibernateLazyInitializer().getIdentifier();
    }
    return null;
}

使用上述代码时,您得到的堆栈跟踪如下:

javax.persistence.EntityNotFoundException: Unable to find entity.Country with id 10
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:291)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:186)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:95)

从堆栈跟踪来看,它表明找不到 ID 为 10 的 entity.Country。尽管数据库中存在该国家的条目,但在不调试的情况下运行时会引发 EntityNotFoundException

您已经尝试升级 Hibernate 到更高版本,但似乎没有解决问题。可能需要检查以下方向或解决方案:

  1. 事务管理: 确保在查询数据库时使用适当的事务管理。有时,事务不会正确配置,导致无法找到实体。

  2. 缓存: 如果启用了缓存,尝试清除缓存并重新运行代码,看看是否有所帮助。

  3. Auditing配置: 确保您的 Hibernate Envers 配置正确。可能需要检查 Envers 的版本与 Hibernate 版本的兼容性,并确保在审计表中正确记录了实体的更改。

  4. 日志: 使用日志来详细了解在代码执行期间发生了什么。这可能有助于确定问题所在。

  5. Hibernate 和 JBoss 版本: 确保所使用的 Hibernate 和 JBoss 版本与您的代码和配置兼容。有时,特定版本之间可能存在问题或不兼容性。

请根据这些方向尝试查找问题的解决方案。如果问题仍然存在,您可能需要深入调查或考虑向 Hibernate 或 JBoss 社区寻求支持。

英文:

Having a problem with upgrading hibernate to 5.3+ with the method calling getHibernateLazyInitializer().getIdentifier() on a HibernateProxy which is loaded with AuditedReader from hibernate envers.

The following example is what I have in code:

@Entity
@Audited
public class Person {
    @Id
    private Long id;
    
    @Column(name="surname")
    private String name;

    @JoinColumn(name="country_id", foreignKey = 
@javax.persistence.ForeignKey(name="FK_country_id"))
    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    private Country country;
}

@Entity
@Audited
public class Country {
    @Id
    public Long id;

    @Column(name="countryName")
    public String countryName;
}


/// Code in another class which I want to get the ID of the country from the Person that comes from the Audited Table of hibernate envers
/// The field is a reflection of which variable it needs to get out of the object
/// field = "country" which needs to get from the personObject
private static Object getId(Object personObject, Field field) throws IllegalAccessException {
    Object countryObject = field.get(value);
    if (object instanceof HibernateProxy) {
        return ((HibernateProxy)countryObject).getHibernateLazyInitializer().getIdentifier();
    }
    return null;
}

The stacktrace which I get using the code is:

javax.persistence.EntityNotFoundException: Unable to find entity.Country with id 10
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:291)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:186)
	at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:95)

The entry of the country is in the database so it exist, also when I debug with Intellij and evaluate the ((HibernateProxy)countryObject).getHibernateLazyInitializer(), it will return the object but if I let it run without debug I'll get EntityNotFoundException.

Already spended hours to figure how to fix it, even upgrading hibernate to a higher version but it doesn't seems to fix it. Someone knows in which direction or solution I can look at.

Thanks

PS: We are using the JBoss 7.4 EAP with patch 11, so using all of their dependencies (the important usage for this code is hibernate-core-5.3.29.Final-redhat-00001 and hibernate-envers-5.3.28.Final-redhat-000015.3.28.Final-redhat-00001 also using javax.persistence.api).

答案1

得分: 1

今天我解决了这个问题,我们从 Hibernate 3.x 升级到 Hibernate 5.x,((HibernateProxy)countryObject).getHibernateLazyInitializer().getIdentifier() 这个方法发生了变化。在 Hibernate 3.x 中,它直接返回对象的标识符,但在 Hibernate 5.x 中,当你调用这个方法时,它会初始化对象,从而引发了未找到异常。

// 来自 org.hibernate.proxy.AbstractLazyInitializer Hibernate 5.x
@Override
public final Serializable getIdentifier() {
	if ( isUninitialized() && isInitializeProxyWhenAccessingIdentifier() ) {
		initialize(); // <-- 这导致了实体未找到异常
	}
	return id;
}

因此,为了解决这个问题,我们使用了
((HibernateProxy)countryObject).getHibernateLazyInitializer().getInternalIdentifier(),它只返回标识符而不初始化对象,因为我们只需要标识符。

英文:

Today I have solved the issue, We went from hibernate 3.x to hibernate 5.x and there was a change in the ((HibernateProxy)countryObject).getHibernateLazyInitializer().getIdentifier(). The hibernate 3.x returns directly the id of the object but in hibernate 5.x when you call this method it will initialize the object which cause the not found exception.

// from org.hibernate.proxy.AbstractLazyInitializer hibernate 5.x
@Override
public final Serializable getIdentifier() {
	if ( isUninitialized() &amp;&amp; isInitializeProxyWhenAccessingIdentifier() ) {
		initialize(); // &lt;-- this causes the entity not found exception
	}
	return id;
}

So to fix this we used
((HibernateProxy)countryObject).getHibernateLazyInitializer().getInternalIdentifier() which only returns the id and not initialize the object because we only needed the Id.

huangapple
  • 本文由 发表于 2023年6月29日 04:05:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76576386.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定