mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Query cache bug, which produces wrong results (#1584)
This commit is contained in:
committed by
Rob Bygrave
parent
baa3909c63
commit
b403942491
+20
@@ -0,0 +1,20 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Acl {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
protected Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Entity
|
||||
public class AclContainerRelation {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
protected Long id;
|
||||
|
||||
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
|
||||
@NotNull
|
||||
private Contract container;
|
||||
|
||||
@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
|
||||
@NotNull
|
||||
private Acl aclEntry;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Contract getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public void setContainer(final Contract container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public Acl getAclEntry() {
|
||||
return aclEntry;
|
||||
}
|
||||
|
||||
public void setAclEntry(final Acl aclEntry) {
|
||||
this.aclEntry = aclEntry;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.tests.query.cache;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
@Entity
|
||||
public class Contract {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
protected Long id;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "contract")
|
||||
private List<Position> positions;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "container", fetch = FetchType.LAZY)
|
||||
@Nonnull
|
||||
private List<AclContainerRelation> aclEntries = new ArrayList<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Position> getPositions() {
|
||||
return positions;
|
||||
}
|
||||
|
||||
public void setPositions(final List<Position> positions) {
|
||||
this.positions = positions;
|
||||
}
|
||||
|
||||
public List<AclContainerRelation> getAclEntries() {
|
||||
return aclEntries;
|
||||
}
|
||||
|
||||
public void setAclEntries(final List<AclContainerRelation> aclEntries) {
|
||||
this.aclEntries = aclEntries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Entity
|
||||
public class ContractCosts {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
protected Long id;
|
||||
|
||||
@NotNull
|
||||
@ManyToOne(cascade = {}, optional = false)
|
||||
private Position position;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(final Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
|
||||
public class Main1 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestDistinct test = new TestDistinct();
|
||||
test.testMissingUnique();
|
||||
// executed query:
|
||||
// select t0.id, t0.position_id from contract_costs t0
|
||||
// join position t1 on t1.id = t0.position_id
|
||||
// join contract t2 on t2.id = t1.contract_id
|
||||
// left join acl_container_relation t3 on t3.container_id = t2.id
|
||||
// where t3.acl_entry_id in (?, ? ) ; --bind(Array[2]={1,2})
|
||||
|
||||
// Test will fail:
|
||||
// Expected size:<1> but was:<2> in:
|
||||
// <[org.tests.query.cache.ContractCosts@1, org.tests.query.cache.ContractCosts@1]>
|
||||
// at org.tests.query.cache.TestDistinct.testMissingUnique(TestDistinct.java:49)
|
||||
// at org.tests.query.cache.Main1.main(Main1.java:7)
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
|
||||
public class Main2 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestDistinct test = new TestDistinct();
|
||||
Ebean.find(ContractCosts.class).where()
|
||||
.in("position.contract.aclEntries.aclEntry.id",1L, 2L, 3L).findList(); // <-- will fix some cache issue?
|
||||
test.testMissingUnique();
|
||||
|
||||
// executed query:
|
||||
// select distinct t0.id, t0.position_id from contract_costs t0
|
||||
// join position u1 on u1.id = t0.position_id
|
||||
// join contract u2 on u2.id = u1.contract_id
|
||||
// join acl_container_relation u3 on u3.container_id = u2.id
|
||||
// where u3.acl_entry_id in (?, ? ) ; --bind(Array[2]={1,2})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.tests.query.cache;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class Position {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
protected Long id;
|
||||
|
||||
@ManyToOne(cascade = {}, optional = false)
|
||||
private Contract contract;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Contract getContract() {
|
||||
return contract;
|
||||
}
|
||||
|
||||
public void setContract(final Contract contract) {
|
||||
this.contract = contract;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.tests.query.cache;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.ExpressionList;
|
||||
|
||||
public class TestDistinct extends BaseTestCase {
|
||||
/**
|
||||
* The call of {@link #positionsQuery} {@link ExpressionList#findList()} causes the following use of {@link #costsQuery(UUID...)} to not
|
||||
* use distinct and return the wrong number of results.
|
||||
*/
|
||||
@Test
|
||||
public void testMissingUnique() {
|
||||
Acl acl = new Acl();
|
||||
Ebean.save(acl);
|
||||
Acl acl2 = new Acl();
|
||||
Ebean.save(acl2);
|
||||
Contract contract = new Contract();
|
||||
AclContainerRelation rel1 = new AclContainerRelation();
|
||||
rel1.setAclEntry(acl);
|
||||
rel1.setContainer(contract);
|
||||
AclContainerRelation rel2 = new AclContainerRelation();
|
||||
rel2.setAclEntry(acl2);
|
||||
rel2.setContainer(contract);
|
||||
contract.getAclEntries().add(rel1);
|
||||
contract.getAclEntries().add(rel2);
|
||||
Position pos = new Position();
|
||||
pos.setContract(contract);
|
||||
contract.getPositions().add(pos);
|
||||
Ebean.save(contract);
|
||||
ContractCosts cost = new ContractCosts();
|
||||
cost.setPosition(pos);
|
||||
Ebean.save(cost);
|
||||
|
||||
//costsQuery(acl.getId(), acl2.getId()).findCount();
|
||||
|
||||
// the between causes the error
|
||||
List<Position> positions = positionsQuery(acl.getId()).findList();
|
||||
// the between causes the error
|
||||
|
||||
System.out.println("The error, query without distinct:");
|
||||
List<ContractCosts> costs = costsQuery(acl.getId(), acl2.getId()).findList();
|
||||
assertThat(costs).hasSize(1);
|
||||
}
|
||||
|
||||
public ExpressionList<Position> positionsQuery(final Long aclId) {
|
||||
return Ebean.find(Position.class).where().eq("contract.aclEntries.aclEntry.id", aclId);
|
||||
}
|
||||
|
||||
public ExpressionList<ContractCosts> costsQuery(final Long... aclId) {
|
||||
return Ebean.find(ContractCosts.class).where().in("position.contract.aclEntries.aclEntry.id", aclId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user