[JIRA] (HHH-17049) Extra records created for entities created in constructor
by Rob Scala (JIRA)
Rob Scala ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiY2YwY2MyZjIw... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-17049?atlOrigin=eyJpIjoiY2YwY2... ) HHH-17049 ( https://hibernate.atlassian.net/browse/HHH-17049?atlOrigin=eyJpIjoiY2YwY2... ) Extra records created for entities created in constructor ( https://hibernate.atlassian.net/browse/HHH-17049?atlOrigin=eyJpIjoiY2YwY2... )
Issue Type: Bug Affects Versions: 6.3.0.CR1 Assignee: Unassigned Components: hibernate-core Created: 08/Aug/2023 13:00 PM Environment: Hibernate 6.3.0.CR1
H2 database
bytecode enhancement on Priority: Major Reporter: Rob Scala ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... )
I have two cases where entities created in a constructor of another entity are persisted in the next transaction, even after the entity is replaced upon loading from the database. For example:
@Entity
public class Person {
@Id @GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
@OneToOne(orphanRemoval = true , cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private ContactInfo contactInfo = new ContactInfo();
private String firstName;
...
}
In some conditions, when I load a Person object (entityManager.find), then set its firstName and commit the transaction, the firstName is changed, but an extra ContactInfo record is unexpectedly created. I expect the ContactInfo instance that was created in the constructor to be discarded when the Person entity is loaded with a ContactInfo record from the database. The database ends up with unreferenced records.
This only happens for me when using bytecode enhancement. I have two test cases that reproduce this behavior.
One involves a bi-directional OneToOne relationship. Here is the repo:
git(a)github.com :robscala/extra_inserts_OneToOne_bi_test.git
@Entity public class Person {
@Id @GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
private String firstName;
@OneToOne(orphanRemoval= true , cascade={CascadeType.PERSIST, CascadeType.REMOVE}, fetch=FetchType.LAZY)
private LoginAccount loginAccount = new LoginAccount();
}
@Entity public class LoginAccount {
@Id @GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
private String name;
@OneToOne(orphanRemoval= true , cascade= CascadeType.ALL, fetch= FetchType.LAZY)
private AccountPreferences accountPreferences = new AccountPreferences();
@OneToOne(mappedBy = "loginAccount" )
private Person owner;
}
@Entity public class AccountPreferences {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private boolean open = false ;
}
In this case, after loading a Person and performing a transaction, an extra record in the AccountPreferences table is created.
The other case involves a polymorphic class, Company. Here is the repo:
git(a)github.com :robscala/extra_inserts_polymorphic_test.git
@Entity
public class Person {
@Id @GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
private String firstName;
@OneToOne(orphanRemoval = true , cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private ContactInfo contactInfo = new ContactInfo();
@ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
private Company company;
}
@Entity
@Inheritance(strategy= InheritanceType.JOINED)
@DiscriminatorColumn(name= "CompanyType" , discriminatorType= DiscriminatorType.INTEGER)
public abstract class Company {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
protected long id;
@OneToOne(orphanRemoval= true , cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
private ContactInfo contactInfo = new ContactInfo();
}
@Entity
@DiscriminatorValue( "9" )
public class CustomerCompany extends Company {
private String zipCode;
@ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REMOVE})
private CustomerCompany parent;
}
In this case, after loading a Person and performing a transaction, an extra record in the ContactInfo table is created.
( https://hibernate.atlassian.net/browse/HHH-17049#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-17049#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100233- sha1:7fb7fe8 )
1 year, 1 month
[JIRA] (HHH-16934) Fetching multiple fields of the same base class with InheritanceType.SINGLE_TABLE throws PropertyAccessException
by Seong Lee (JIRA)
Seong Lee ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=712020%... ) *commented* on HHH-16934 ( https://hibernate.atlassian.net/browse/HHH-16934?atlOrigin=eyJpIjoiYTQ1M2... )
Re: Fetching multiple fields of the same base class with InheritanceType.SINGLE_TABLE throws PropertyAccessException ( https://hibernate.atlassian.net/browse/HHH-16934?atlOrigin=eyJpIjoiYTQ1M2... )
Hello, I am seeing this exact same error when using a InheritanceType.JOINED type on the parent. This was working fine on SpringBoot 3.0.6
I am on SpringBoot 3.1.2 , which uses Hibernate 6.2.6.Final. I’ve also tried forcing the 6.3.0.CR1 version and still see the error. This is written in Kotlin.
@Entity
@Table(name = "Resource")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "RESOURCE_TYPE_CD", discriminatorType = DiscriminatorType.INTEGER, columnDefinition = "INT")
abstract class Resource(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "RESOURCE_ID_SEQ")
@SequenceGenerator(name = "RESOURCE_ID_SEQ", sequenceName = "RESOURCE_ID_SEQ", allocationSize = 1)
override var id: Long? = null,
@Column(name = "RESOURCE_TYPE_CD", insertable = false, updatable = false)
open var resourceType: ResourceType
): MutableAuditableBaseJpa<Long>() { ... }
@Entity
@Table(name = "RESOURCE_FUTURE_ROLE")
@DiscriminatorValue("1")
class FutureRole(
...
): Resource(null, ResourceType.FUTURE_ROLE) { ... }
@Entity
@Table(name = "RESOURCE_CURRENT_ROLE")
@DiscriminatorValue("2")
class CurrentRole(
...
): Resource(null, ResourceType.CURRENT_ROLE) { ... }
@Entity
@Table(name = "RECORD")
open class Record(
@Column(name = "RESOURCE_ID") override var resourceId: Long,
...
): MutableAuditableBaseJpa<Long>() {
@OneToOne
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name = "RESOURCE_ID", insertable = false, updatable = false)
open var futureRole: FutureRole? = null
@OneToOne
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name = "RESOURCE_ID", insertable = false, updatable = false)
open var employee: CurrentRole? = null
}
Caused by: org.hibernate.PropertyAccessException: Could not set value of type [com.hidden.CurrentRole]: 'com.hidden.Record.futureRole' (setter)
at org.hibernate.property.access.spi.SetterFieldImpl.set(SetterFieldImpl.java:88)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:4360)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.initializeEntityInstance(AbstractEntityInitializer.java:837)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.initializeEntity(AbstractEntityInitializer.java:797)
at org.hibernate.sql.results.graph.entity.AbstractEntityInitializer.initializeInstance(AbstractEntityInitializer.java:783)
at org.hibernate.sql.results.internal.InitializersList.initializeInstance(InitializersList.java:71)
at org.hibernate.sql.results.internal.StandardRowReader.coordinateInitializers(StandardRowReader.java:109)
at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:86)
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:201)
at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:361)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:109)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:305)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:246)
at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:509)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:427)
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:559)
Note: I understand @DiscriminatorColumn is unnecessary for a Joined Inheritance, but this was existing logic I have yet to change.
( https://hibernate.atlassian.net/browse/HHH-16934#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16934#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100233- sha1:7fb7fe8 )
1 year, 1 month