mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Test for #293 - Invalid result rows when ManyToMany "fetch joined" with additional child OneToMany or ManyToMany child relationship fetched
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Level1 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "level1_level4",
|
||||
joinColumns = @JoinColumn(name = "level1_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level4_id", referencedColumnName = "id")
|
||||
)
|
||||
Set<Level4> level4s;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "level1_level2",
|
||||
joinColumns = @JoinColumn(name = "level1_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level2_id", referencedColumnName = "id")
|
||||
)
|
||||
Set<Level2> level2s;
|
||||
|
||||
String name;
|
||||
|
||||
public Level1(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Set<Level2> getLevel2s() {
|
||||
return level2s;
|
||||
}
|
||||
|
||||
public Set<Level4> getLevel4s() {
|
||||
return level4s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class Level2 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
|
||||
@JoinTable(
|
||||
name = "level2_level3",
|
||||
joinColumns = @JoinColumn(name = "level2_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "level3_id", referencedColumnName = "id")
|
||||
)
|
||||
List<Level3> level3s;
|
||||
|
||||
String name;
|
||||
|
||||
public Level2(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Level3> getLevel3s() {
|
||||
return level3s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Level3 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
public Level3(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.tests.level;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Level4 {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
public Level4(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.avaje.tests.level.test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.tests.level.Level1;
|
||||
import com.avaje.tests.level.Level2;
|
||||
import com.avaje.tests.level.Level3;
|
||||
import com.avaje.tests.level.Level4;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ManyToManyTest extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Level4 i = new Level4("i");
|
||||
Level4 ii = new Level4("ii");
|
||||
Level4 iii = new Level4("iii");
|
||||
|
||||
Ebean.save(i);
|
||||
Ebean.save(ii);
|
||||
Ebean.save(iii);
|
||||
|
||||
Level3 a = new Level3("a");
|
||||
Level3 b = new Level3("b");
|
||||
|
||||
Ebean.save(a);
|
||||
Ebean.save(b);
|
||||
|
||||
Level2 one = new Level2("one");
|
||||
Level2 two = new Level2("two");
|
||||
|
||||
Ebean.save(one);
|
||||
Ebean.save(two);
|
||||
|
||||
Level1 x1 = new Level1("x1");
|
||||
Level1 x2 = new Level1("x2");
|
||||
Level1 x3 = new Level1("x3");
|
||||
Level1 x4 = new Level1("x4");
|
||||
Level1 x5 = new Level1("x5");
|
||||
|
||||
x1.getLevel2s().add(one);
|
||||
x2.getLevel2s().add(one);
|
||||
x3.getLevel2s().add(two);
|
||||
x4.getLevel2s().add(two);
|
||||
x5.getLevel2s().add(two);
|
||||
|
||||
x1.getLevel4s().add(i);
|
||||
x1.getLevel4s().add(ii);
|
||||
x2.getLevel4s().add(ii);
|
||||
x2.getLevel4s().add(iii);
|
||||
|
||||
Ebean.save(x1);
|
||||
Ebean.save(x2);
|
||||
Ebean.save(x3);
|
||||
Ebean.save(x4);
|
||||
Ebean.save(x5);
|
||||
|
||||
// this query had the original problem
|
||||
List<Level1> things = Ebean.find(Level1.class)
|
||||
.fetch("level4s")
|
||||
.fetch("level2s")
|
||||
.fetch("level2s.level3s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
|
||||
things = Ebean.find(Level1.class)
|
||||
.fetch("level2s")
|
||||
.fetch("level2s.level3s")
|
||||
.fetch("level4s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
|
||||
things = Ebean.find(Level1.class)
|
||||
.fetch("level2s")
|
||||
.fetch("level4s")
|
||||
.order().asc("id")
|
||||
.findList();
|
||||
|
||||
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
|
||||
|
||||
} finally {
|
||||
Ebean.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateObjectGraph(Level4 i, Level4 ii, Level4 iii, Level2 one, Level2 two, Level1 x1, Level1 x2, Level1 x3, Level1 x4, Level1 x5, List<Level1> things) {
|
||||
|
||||
assertEquals(5, things.size());
|
||||
|
||||
// x1's are in order expected
|
||||
assertEquals(x1.getId(), things.get(0).getId());
|
||||
assertEquals(x2.getId(), things.get(1).getId());
|
||||
assertEquals(x3.getId(), things.get(2).getId());
|
||||
assertEquals(x4.getId(), things.get(3).getId());
|
||||
assertEquals(x5.getId(), things.get(4).getId());
|
||||
|
||||
// x1 to level4s
|
||||
assertEquals(2, things.get(0).getLevel4s().size());
|
||||
assertTrue(contains(things.get(0).getLevel4s(), i));
|
||||
assertTrue(contains(things.get(0).getLevel4s(), ii));
|
||||
|
||||
// x2 to level4s
|
||||
assertEquals(2, things.get(1).getLevel4s().size());
|
||||
assertTrue(contains(things.get(1).getLevel4s(), ii));
|
||||
assertTrue(contains(things.get(1).getLevel4s(), iii));
|
||||
|
||||
// x3 etc to level4s
|
||||
assertEquals(0, things.get(2).getLevel4s().size());
|
||||
assertEquals(0, things.get(3).getLevel4s().size());
|
||||
assertEquals(0, things.get(4).getLevel4s().size());
|
||||
|
||||
// level2 relationships
|
||||
for (final Level1 curThing : things) {
|
||||
assertEquals(1, curThing.getLevel2s().size());
|
||||
}
|
||||
assertTrue(contains(things.get(0).getLevel2s(), one));
|
||||
assertTrue(contains(things.get(1).getLevel2s(), one));
|
||||
assertTrue(contains(things.get(2).getLevel2s(), two));
|
||||
assertTrue(contains(things.get(3).getLevel2s(), two));
|
||||
assertTrue(contains(things.get(4).getLevel2s(), two));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if match exists in level4s.
|
||||
*/
|
||||
private boolean contains(Set<Level4> level4s, Level4 match) {
|
||||
for (Level4 level4 : level4s) {
|
||||
if (level4.getId().equals(match.getId()) && level4.getName().equals(match.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if match exists in level2s.
|
||||
*/
|
||||
private boolean contains(Set<Level2> level2s, Level2 match) {
|
||||
for (Level2 level2 : level2s) {
|
||||
if (level2.getId().equals(match.getId()) && level2.getName().equals(match.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user