HHH-13945: catch PersistenceException during envers unproxy the field value, and fallback to using proxy entity
This commit is contained in:
parent
2228bd238e
commit
2404ff56ab
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.manytoone.lazy;
|
||||
|
||||
import org.hibernate.envers.NotAudited;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luke Chen
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "child_user")
|
||||
public class ChildUser extends User {
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE)
|
||||
@NotAudited
|
||||
private List<Shipment> shipmentList;
|
||||
|
||||
ChildUser() {
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.manytoone.lazy;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.envers.configuration.EnversSettings;
|
||||
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
|
||||
import org.hibernate.envers.test.Priority;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests that proxies can still be resolved correctly in ToOneIdMapper even the object is already deleted and can't
|
||||
* find in cache. This can happen if the deleted object is an inherited object, and when the child object is deleted,
|
||||
* we cannot find the object with the parent class name anymore.
|
||||
*
|
||||
* @author Luke Chen
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-13945")
|
||||
public class ManyToOneLazyDeleteTest extends BaseEnversFunctionalTestCase {
|
||||
private Long shipmentId;
|
||||
private User user;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Shipment.class, Address.class, AddressVersion.class, User.class, ChildUser.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@Priority(10)
|
||||
public void initData() {
|
||||
|
||||
this.shipmentId = doInHibernate( this::sessionFactory, session -> {
|
||||
final Shipment shipment = new Shipment( Instant.now(), "system", Instant.now().plus( Duration.ofDays( 3 ) ), "abcd123", null, null );
|
||||
session.persist( shipment );
|
||||
session.flush();
|
||||
|
||||
final Address origin = new Address( Instant.now(), "system", "Valencia#1" );
|
||||
final Address destination = new Address( Instant.now(), "system", "Madrid#3" );
|
||||
final AddressVersion originVersion0 = origin.addInitialVersion( "Poligono Manises" );
|
||||
final AddressVersion destinationVersion0 = destination.addInitialVersion( "Poligono Alcobendas" );
|
||||
user = new ChildUser();
|
||||
session.persist( origin );
|
||||
session.persist( destination );
|
||||
session.persist( user );
|
||||
|
||||
session.flush();
|
||||
shipment.setUser( user );
|
||||
shipment.setOrigin( originVersion0 );
|
||||
shipment.setDestination( destinationVersion0 );
|
||||
|
||||
session.merge( shipment );
|
||||
session.flush();
|
||||
|
||||
return shipment.getId();
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
final Shipment shipment = session.get( Shipment.class, shipmentId );
|
||||
session.remove(shipment);
|
||||
// Cast the User instance to the ChildUser, and delete the child one, so the cache for
|
||||
// the User instance will not be there, and entityNotFound exception will be thrown while envers processing it
|
||||
ChildUser childUser = session.get(ChildUser.class, user.getId());
|
||||
session.remove(childUser);
|
||||
|
||||
session.flush();
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
super.addSettings( settings );
|
||||
|
||||
settings.put(EnversSettings.STORE_DATA_AT_DELETE, "true");
|
||||
}
|
||||
}
|
|
@ -62,6 +62,11 @@ public class Shipment extends BaseDomainEntity {
|
|||
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
|
||||
private AddressVersion destination;
|
||||
|
||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = true)
|
||||
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
|
||||
private User user;
|
||||
|
||||
Shipment() {
|
||||
}
|
||||
|
||||
|
@ -104,4 +109,8 @@ public class Shipment extends BaseDomainEntity {
|
|||
public void setDestination(AddressVersion destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.envers.test.integration.manytoone.lazy;
|
||||
|
||||
import org.hibernate.envers.NotAudited;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luke Chen
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
protected long id = 0;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE)
|
||||
@NotAudited
|
||||
private List<Shipment> shipmentList;
|
||||
|
||||
User() {
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue