Skip to content

HHH-18436: Reproducer for wrong ordering if @OrderBy is used together… #410

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
68 changes: 68 additions & 0 deletions orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/Level1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.hibernate.bugs;

import java.util.LinkedHashSet;
import java.util.Set;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.NamedEntityGraphs;
import jakarta.persistence.NamedSubgraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;

@Entity
@NamedEntityGraphs({
@NamedEntityGraph(
name = "level1_loadAll",
attributeNodes = {
@NamedAttributeNode(value = "childs", subgraph = "subgraph.childs")
},
subgraphs = {
@NamedSubgraph(
name = "subgraph.childs",
attributeNodes = {
@NamedAttributeNode(value = "childs")
}
)
}
)
})
public class Level1 {

@Id
private Long id;

@OneToMany(fetch = FetchType.LAZY,
mappedBy = "parent",
cascade = CascadeType.ALL,
orphanRemoval = true)
@OrderBy("id")
private Set<Level2> childs = new LinkedHashSet<>();

public Level1() {
}

public Level1(Long id) {
this.id = id;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Set<Level2> getChilds() {
return childs;
}

public void setChilds(Set<Level2> childs) {
this.childs = childs;
}

}
64 changes: 64 additions & 0 deletions orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/Level2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.hibernate.bugs;

import java.util.LinkedHashSet;
import java.util.Set;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;

@Entity
public class Level2 {

@Id
Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "parent_id", nullable = false)
private Level1 parent;

@OneToMany(fetch = FetchType.LAZY,
mappedBy = "parent",
cascade = CascadeType.ALL,
orphanRemoval = true)
@OrderBy("id")
private Set<Level3> childs = new LinkedHashSet<>();


public Level2() {
}

public Level2(Level1 parent, Long id) {
this.parent = parent;
this.id = id;
parent.getChilds().add(this);
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Level1 getParent() {
return parent;
}

public void setParent(Level1 parent) {
this.parent = parent;
}

public Set<Level3> getChilds() {
return childs;
}

public void setChilds(Set<Level3> childs) {
this.childs = childs;
}
}
43 changes: 43 additions & 0 deletions orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/Level3.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.hibernate.bugs;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;

@Entity
public class Level3 {

@Id
Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "parent_id", nullable = false)
private Level2 parent;

public Level3() {
}

public Level3(Level2 parent, Long id) {
this.parent = parent;
this.id = id;
parent.getChilds().add(this);
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Level2 getParent() {
return parent;
}

public void setParent(Level2 parent) {
this.parent = parent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
*/
package org.hibernate.bugs;

import java.util.HashMap;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Assert;
import org.junit.Test;

/**
Expand All @@ -37,8 +40,9 @@ public class ORMUnitTestCase extends BaseCoreFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
// Foo.class,
// Bar.class
Level1.class,
Level2.class,
Level3.class,
};
}

Expand Down Expand Up @@ -68,10 +72,64 @@ protected void configure(Configuration configuration) {

// Add your tests, using standard JUnit.
@Test
public void hhh123Test() throws Exception {
public void hhh18436Test() throws Exception {
// BaseCoreFunctionalTestCase automatically creates the SessionFactory and provides the Session.
Session s = openSession();
Transaction tx = s.beginTransaction();
Level1 root = new Level1(1L);

Level2 child1 = new Level2(root, 1L);
Level2 child2 = new Level2(root,2L);
Level2 child3 = new Level2(root,3L);

new Level3(child2,1L);

s.persist(root);
s.flush();
s.clear();

Level1 loadedWithoutEntityGraph = s.find(Level1.class, 1L);

long i = 1;
for (Level2 child : loadedWithoutEntityGraph.getChilds()) {
Assert.assertEquals("Childs not in expected order", Long.valueOf(i), child.getId());
i++;
}

tx.commit();
s.close();
}

// Add your tests, using standard JUnit.
@Test
public void hhh18436TestEntitygraph() throws Exception {
// BaseCoreFunctionalTestCase automatically creates the SessionFactory and provides the Session.
Session s = openSession();
Transaction tx = s.beginTransaction();
Level1 root = new Level1(1L);

Level2 child1 = new Level2(root, 1L);
Level2 child2 = new Level2(root,2L);
Level2 child3 = new Level2(root,3L);

new Level3(child2,1L);

s.persist(root);
s.flush();
s.clear();

// Hints
Map<String, Object> hints = new HashMap<>();
hints.put("jakarta.persistence.loadgraph", s.getEntityGraph("level1_loadAll"));

Level1 loadedWithEntityGraph = s.find(Level1.class, 1L, hints);

long i = 1;
for (Level2 child : loadedWithEntityGraph.getChilds()) {
Assert.assertEquals("Childs not in expected order", Long.valueOf(i), child.getId());
i++;
}

// Do stuff...
tx.commit();
s.close();
Expand Down