I have the following table schema, where a simulation has many searches and any search has many properties.
Since I would like to persist a Simulation entity with its searches and their properties all at once, I mapped my entity like this:
Simulation.java
@Data
@EqualsAndHashCode(of = "id")
@ToString(exclude = "searches")
@Entity
@Table(name = "SIMULATION")
public class Simulation implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "simulation_generator")
@SequenceGenerator(name = "simulation_generator", sequenceName = "SIMULATION_SEQ", allocationSize = 1)
private Long id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "SIMULATION_ID")
private Set<SimulationSearch> searches = new HashSet<>(0);
// other fields
}
SimulationSearch.java
@Data
@EqualsAndHashCode(of = "id")
@ToString(exclude = "properties")
@Entity
@Table(name = "SIM_SEARCH")
public class SimulationSearch implements Serializable {
@EmbeddedId
private SimulationSearchId id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumns({
@JoinColumn(name = "SIMULATION_ID", referencedColumnName = "SIMULATION_ID"),
@JoinColumn(name = "POSITION", referencedColumnName = "POSITION")
})
private Set<SimulationSearchProperty> properties = new HashSet<>(0);
// other fields...
@Data
public static class SimulationSearchId implements Serializable {
@ManyToOne
@JoinColumn(name = "SIMULATION_ID", insertable = false, updatable = false)
private Simulation simulation;
private int position;
}
}
SimulationSearchProperties.java
@Data
@EqualsAndHashCode(of = "id")
@Entity
@Table(name = "SIM_SEARCH_PROPERTY")
public class SimulationSearchProperty implements Serializable {
@EmbeddedId
private SimulationSearchPropertyId id;
private String value;
@Data
public static class SimulationSearchPropertyId implements Serializable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "SIMULATION_ID", referencedColumnName = "SIMULATION_ID", insertable = false, updatable = false),
@JoinColumn(name = "POSITION", referencedColumnName = "POSITION", insertable = false, updatable = false)
})
private SimulationSearch search;
private String label;
}
}
What happens is that Hibernate keeps printing the following query untill it goes on StackOverflowError.
select simulation0_.*, searches1_.*, properties5_.*
from simulation simulation0_
left outer join sim_search searches1_ on simulation0_.id = searches1_.simulation_id
left outer join sim_search_property properties5_ on searches1_.position = properties5_.position and searches1_.simulation_id = properties5_.simulation_id
where simulation0_.id = ?
While mapping between Simulation
and SimulationSearch
is very similar to SimulationSearch
and SimulationSearchProperty
mapping, this error started happening when I set ManyToOne
annotation of SimulationSearch#properties
as lazy fetch and didn't stop even if I set SimulationSearchPropertyId#search
as lazy too.
What am I missing?
UPDATES
I'm using Hibernate 4.2.6.Final
Partial stacktrace log:
java.lang.StackOverflowError
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:148)
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:104)
at org.hibernate.engine.spi.QueryParameters.<init>(QueryParameters.java:81)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2114)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3927)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:460)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:429)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:206)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:262)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
at org.hibernate.type.EntityType.resolve(EntityType.java:490)
at org.hibernate.type.ComponentType.resolve(ComponentType.java:667)
at org.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:349)
at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:190)
at org.hibernate.type.ComponentType.hydrate(ComponentType.java:642)
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:775)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:708)
at org.hibernate.loader.Loader.processResultSet(Loader.java:943)
at org.hibernate.loader.Loader.doQuery(Loader.java:911)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:312)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2121)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:82)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:72)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3927)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:460)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:429)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:206)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:262)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:150)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
at org.hibernate.type.EntityType.resolve(EntityType.java:490)
at org.hibernate.type.ComponentType.resolve(ComponentType.java:667)
at org.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:349)
at org.hibernate.type.ManyToOneType.hydrate(ManyToOneType.java:190)
at org.hibernate.type.ComponentType.hydrate(ComponentType.java:642)
at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:775)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:708)
at org.hibernate.loader.Loader.processResultSet(Loader.java:943)
at org.hibernate.loader.Loader.doQuery(Loader.java:911)
...
I've just updated a bit the entity mapping, removing mappedBy
annotation attribute and adding instead @JoinColumn
s annotations.
Now persistence is working fine, but the StackOverflowError is still there when I try to load a single simulation.
I've also cleaned up Hibernate generated sql removing uninteresting pieces of information.