Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,10 @@ public EntityHolder claimEntityHolderIfPossible(
else {
newEntityHolder = null;
}
holder.entityInitializer = initializer;
if ( holder.processingState != processingState ) {
holder.entityInitializer = initializer;
holder.processingState = processingState;
}
return holder;
}

Expand Down Expand Up @@ -2193,7 +2196,8 @@ private static class EntityHolderImpl implements EntityHolder, Serializable {
private Object entity;
private Object proxy;
private @Nullable EntityEntry entityEntry;
private EntityInitializer<?> entityInitializer;
private @Nullable EntityInitializer<?> entityInitializer;
private @Nullable JdbcValuesSourceProcessingState processingState;
private EntityHolderState state;

private EntityHolderImpl() {
Expand Down Expand Up @@ -2231,10 +2235,15 @@ public Object getProxy() {
}

@Override
public EntityInitializer<?> getEntityInitializer() {
public @Nullable EntityInitializer<?> getEntityInitializer() {
return entityInitializer;
}

@Override
public @Nullable JdbcValuesSourceProcessingState getJdbcValuesProcessingState() {
return processingState;
}

@Override
public void markAsReloaded(JdbcValuesSourceProcessingState processingState) {
processingState.registerReloadedEntityHolder( this );
Expand All @@ -2256,8 +2265,9 @@ public boolean isDetached() {
}

@Override
public void resetEntityInitialier(){
public void resetEntityInitialier() {
entityInitializer = null;
processingState = null;
}

public EntityHolderImpl withEntity(EntityKey entityKey, EntityPersister descriptor, Object entity) {
Expand All @@ -2269,7 +2279,11 @@ public EntityHolderImpl withProxy(EntityKey entityKey, EntityPersister descripto
}

public EntityHolderImpl withData(EntityKey entityKey, EntityPersister descriptor, Object entity, Object proxy) {
assert entityKey != null && descriptor != null && entityInitializer == null && state == EntityHolderState.UNINITIALIZED;
assert entityKey != null
&& descriptor != null
&& entityInitializer == null
&& processingState == null
&& state == EntityHolderState.UNINITIALIZED;
this.entityKey = entityKey;
this.descriptor = descriptor;
this.entity = entity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public interface EntityHolder {
* Will be {@code null} if entity is initialized already or the entity holder is not claimed yet.
*/
@Nullable EntityInitializer<?> getEntityInitializer();
/**
* The {@link JdbcValuesSourceProcessingState} for the entity initializer that claims to initialize the entity for this holder.
* Will be {@code null} if entity is initialized already or the entity holder is not claimed yet.
*/
@Nullable JdbcValuesSourceProcessingState getJdbcValuesProcessingState();

/**
* The proxy if there is one and otherwise the entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,12 @@ else if ( isResultInitializer() ) {
}
}
else if ( data.entityHolder.getEntityInitializer() != this ) {
data.setState( State.INITIALIZED );
// The other initializer will take care of initialization
if ( !hasLazyInitializingSubAssemblers ) {
// but we can only skip the initialization phase of this initializer,
// if this initializer does not initialize lazy basic attributes
data.setState( State.INITIALIZED );
}
}
else if ( data.shallowCached ) {
// For shallow cached entities, only the id is available, so ensure we load the data immediately
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,10 @@ protected void initialize(
}
}
else if ( holder.getEntityInitializer() != this ) {
// the entity is already being loaded elsewhere
data.setState( State.INITIALIZED );
// the entity is already being loaded elsewhere in this processing level
if ( holder.getJdbcValuesProcessingState() == data.getRowProcessingState().getJdbcValuesSourceProcessingState() ) {
data.setState( State.INITIALIZED );
}
return;
}
else if ( data.getInstance() == null ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.fetch;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Tuple;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DomainModel(
annotatedClasses = {
FetchModeSubselectAndQueryJoinTest.Node.class,
FetchModeSubselectAndQueryJoinTest.Element.class
}
)
@SessionFactory
@JiraKey( "HHH-19949" )
public class FetchModeSubselectAndQueryJoinTest {

@BeforeAll
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Node basik = new Node( "Child" );
basik.elements.add( new Element( basik ) );
basik.elements.add( new Element( basik ) );
session.persist( basik );
}
);
}

@Test
public void tesSelect(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<Tuple> results = session.createSelectionQuery(
"select distinct n, e from Node n join n.elements e ", Tuple.class ).getResultList();
assertThat( results ).hasSize( 2 );
}
);
}

@Entity(name = "Element")
@Table(name = "Element")
public static class Element {
@Id
@GeneratedValue
Integer id;

@ManyToOne
Node node;

public Element(Node node) {
this.node = node;
}

Element() {
}
}

@Entity(name = "Node")
@Table(name = "Node")
public static class Node {

@Id
@GeneratedValue
Integer id;
String string;

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "node")
@Fetch(FetchMode.SUBSELECT)
List<Element> elements = new ArrayList<>();

public Node(String string) {
this.string = string;
}

Node() {
}
}
}
Loading
Loading