Skip to content

HHH-19137 - NamedEntityGraph entity loading fails with AssertionError #9747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
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
@@ -0,0 +1,160 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.jpa.graphs.embeddedid;

import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.Activity;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.ActivityAnswer;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.ActivityAnswerId;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.ActivityDocument;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.ActivityDocumentId;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.ActivityExerciseId;
import org.hibernate.orm.test.jpa.graphs.embeddedid.entities.Exercise;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;

@Jpa(
annotatedClasses = {
Exercise.class,
Activity.class,
ActivityExerciseId.class,
ActivityAnswer.class,
ActivityAnswerId.class,
ActivityDocument.class,
ActivityDocumentId.class
}
)

@JiraKey(value = "HHH-19137")
public class LoadEntityGraphWithCompositeKeyCollectionsTest {

@AfterEach
public void tearDown(EntityManagerFactoryScope scope) {
scope.releaseEntityManagerFactory();
}

@Test
void testLoadFromEntityWithAllCollectionsFilled(EntityManagerFactoryScope scope) {
scope.inTransaction( entityManager -> {
Activity activityWithAnswersAndDocuments = createActivity();

ActivityAnswer activityAnswer1 = createActivityAnswer(
activityWithAnswersAndDocuments, "question_01",
"answer_01" );
ActivityAnswer activityAnswer2 = createActivityAnswer(
activityWithAnswersAndDocuments, "question_02",
"answer_02" );

Set<ActivityAnswer> answers = new HashSet<>();
answers.add( activityAnswer1 );
answers.add( activityAnswer2 );
activityWithAnswersAndDocuments.setAnswers( answers );

Set<ActivityDocument> documents = new HashSet<>();
documents.add( createActivityDocument( activityWithAnswersAndDocuments, "question_01", "document_01" ) );
activityWithAnswersAndDocuments.setDocuments( documents );

entityManager.persist( activityWithAnswersAndDocuments );
}
);

scope.inTransaction( entityManager -> {

List<Activity> activities = buildQuery( entityManager ).getResultList();

assertEquals( 1, activities.size() );
assertEquals( 2, activities.get( 0 ).getAnswers().size() );
assertEquals( 1, activities.get( 0 ).getDocuments().size() );

} );
}

@Test
void testLoadFromEntityWithOneEmptyCollection(EntityManagerFactoryScope scope) {
System.out.println( "!! one empty collection" );
scope.inTransaction( entityManager -> {
Activity activityWithoutDocuments = createActivity();

ActivityAnswer activityAnswer1 = createActivityAnswer( activityWithoutDocuments, "question_01",
"answer_01" );
ActivityAnswer activityAnswer2 = createActivityAnswer( activityWithoutDocuments, "question_02",
"answer_02" );

Set<ActivityAnswer> answers = new HashSet<>();
answers.add( activityAnswer1 );
answers.add( activityAnswer2 );
activityWithoutDocuments.setAnswers( answers );

entityManager.persist( activityWithoutDocuments );
}
);

scope.inTransaction( entityManager -> {
List<Activity> activities = buildQuery( entityManager ).getResultList();

assertEquals( 1, activities.size() );
assertEquals( 2, activities.get( 0 ).getAnswers().size() );
assertEquals( 0, activities.get( 0 ).getDocuments().size() );
} );
}

private TypedQuery<Activity> buildQuery(EntityManager entityManager) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Activity> query = builder.createQuery( Activity.class );

Root<Activity> root = query.from( Activity.class );
query.select( root )
.where( builder.equal( root.get( "activityExerciseId" ).get( "exerciseId" ), 1 ) );

TypedQuery<Activity> typedQuery = entityManager.createQuery( query );
String graphType = GraphSemantic.LOAD.getJakartaHintName();
String entityGraphName = "with.collections";
typedQuery.setHint( graphType, entityManager.getEntityGraph( entityGraphName ) );

return typedQuery;
}

private Activity createActivity() {
Exercise exercise = new Exercise();
Activity activity = new Activity();
ActivityExerciseId activityExerciseId = new ActivityExerciseId();
activityExerciseId.setExerciseId( exercise.getId() );
activityExerciseId.setActivityId( "general-ref" );
activity.setExercise( exercise ).setActivityExerciseId( activityExerciseId );
return activity;
}

private ActivityAnswer createActivityAnswer(Activity activity, String questionId, String answer) {
ActivityAnswer newAnswer = new ActivityAnswer();
ActivityAnswerId answerId = new ActivityAnswerId();
answerId.setActivity( activity ).setQuestionId( questionId );
newAnswer.setActivityAnswerId( answerId );
newAnswer.setAnswer( answer );
return newAnswer;
}

private ActivityDocument createActivityDocument(Activity activity, String questionId, String name) {
ActivityDocument newDocument = new ActivityDocument();
ActivityDocumentId documentId = new ActivityDocumentId();
documentId.setActivity( activity ).setQuestionId( questionId );
newDocument.setActivityDocumentId( documentId );
newDocument.setName( name );
return newDocument;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.jpa.graphs.embeddedid.entities;

import jakarta.persistence.CascadeType;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

@Entity
@Table(name = "activities")
@NamedEntityGraph(name = "with.collections",
attributeNodes = {
@NamedAttributeNode(value = "answers"),
@NamedAttributeNode(value = "documents")
}
)
public class Activity {

@EmbeddedId
private ActivityExerciseId activityExerciseId;

@MapsId("exerciseId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "exercise_id")
private Exercise exercise;

@OneToMany(mappedBy = "activityAnswerId.activity", cascade = CascadeType.ALL)
private Set<ActivityAnswer> answers = new HashSet<>();

@OneToMany(mappedBy = "activityDocumentId.activity", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<ActivityDocument> documents = new HashSet<>();

public Activity setActivityExerciseId(ActivityExerciseId activityExerciseId) {
this.activityExerciseId = activityExerciseId;
return this;
}

public Set<ActivityAnswer> getAnswers() {
return answers;
}

public Set<ActivityDocument> getDocuments() {
return documents;
}

public Activity setExercise(Exercise exercise) {
this.exercise = exercise;
return this;
}

public Activity setAnswers(Set<ActivityAnswer> answers) {
this.answers = answers;
return this;
}

public Activity setDocuments(Set<ActivityDocument> documents) {
this.documents = documents;
return this;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
Activity that = (Activity) o;
return Objects.equals( activityExerciseId, that.activityExerciseId );
}

@Override
public int hashCode() {
return Objects.hashCode( activityExerciseId );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.jpa.graphs.embeddedid.entities;

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

import java.util.Objects;

@Entity
@Table(name = "activity_answers")
public class ActivityAnswer {

@EmbeddedId
private ActivityAnswerId activityAnswerId;

private String answer;

public ActivityAnswer setActivityAnswerId(ActivityAnswerId activityAnswerId) {
this.activityAnswerId = activityAnswerId;
return this;
}

public ActivityAnswer setAnswer(String answer) {
this.answer = answer;
return this;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ActivityAnswer that = (ActivityAnswer) o;
return Objects.equals( activityAnswerId, that.activityAnswerId );
}

@Override
public int hashCode() {
return Objects.hashCode( activityAnswerId );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.jpa.graphs.embeddedid.entities;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;

import java.util.Objects;

@Embeddable
public class ActivityAnswerId {

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "exercise_id", referencedColumnName = "exercise_id"),
@JoinColumn(name = "activity_id", referencedColumnName = "activity_id")
})
private Activity activity;

@Column(name = "question_id")
private String questionId;

public ActivityAnswerId() {
}

public ActivityAnswerId setActivity(Activity activity) {
this.activity = activity;
return this;
}

public ActivityAnswerId setQuestionId(String questionId) {
this.questionId = questionId;
return this;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ActivityAnswerId that = (ActivityAnswerId) o;
return Objects.equals( activity, that.activity ) && Objects.equals( questionId, that.questionId );
}

@Override
public int hashCode() {
return Objects.hash( activity, questionId );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.jpa.graphs.embeddedid.entities;

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

import java.util.Objects;

@Entity
@Table(name = "activity_documents")
public class ActivityDocument {

@EmbeddedId
private ActivityDocumentId activityDocumentId;

private String name;

public ActivityDocument setActivityDocumentId(ActivityDocumentId activityDocumentId) {
this.activityDocumentId = activityDocumentId;
return this;
}

public ActivityDocument setName(String name) {
this.name = name;
return this;
}

@Override
public boolean equals(Object o) {
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ActivityDocument that = (ActivityDocument) o;
return Objects.equals( activityDocumentId, that.activityDocumentId );
}

@Override
public int hashCode() {
return Objects.hashCode( activityDocumentId );
}
}
Loading
Loading