Fix for #154 - @OrderBy on a @OneToMany property is not used when lazy loading

This commit is contained in:
Rob Bygrave
2014-06-26 00:37:31 +12:00
parent 3e33ece65a
commit 1109d412e7
5 changed files with 157 additions and 5 deletions
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
import java.util.List;
import junit.framework.Assert;
import org.junit.Assert;
import org.junit.Test;
import com.avaje.ebean.BaseTestCase;
@@ -25,6 +24,8 @@ public class TestSharedInstancePropagation extends BaseTestCase {
ResetBasicData.reset();
Ebean.getServerCacheManager().clearAll();
Order order = Ebean.find(Order.class)
.setAutofetch(false)
.setUseCache(true)
@@ -1,5 +1,8 @@
package com.avaje.tests.query.orderby;
import java.util.List;
import org.avaje.ebeantest.LoggedSqlCollector;
import org.junit.Assert;
import org.junit.Test;
@@ -7,6 +10,7 @@ import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.Order;
import com.avaje.tests.model.basic.OrderDetail;
import com.avaje.tests.model.basic.ResetBasicData;
public class TestOrderByWithMany extends BaseTestCase {
@@ -16,6 +20,7 @@ public class TestOrderByWithMany extends BaseTestCase {
ResetBasicData.reset();
checkWithLazyLoadingOnBuiltInMany();
checkWithBuiltInManyBasic();
checkWithBuiltInMany();
checkAppendId();
@@ -26,17 +31,42 @@ public class TestOrderByWithMany extends BaseTestCase {
checkAlreadyIncluded2();
}
private void checkWithLazyLoadingOnBuiltInMany() {
LoggedSqlCollector.start();
Query<Order> query = Ebean.find(Order.class);
// a query that ensures we are going to lazy load on the details
List<Order> orders = query.findList();
for (Order order : orders) {
// invoke lazy loading
List<OrderDetail> details = order.getDetails();
details.size();
}
// first one is the main query and others are lazy loading queries
List<String> loggedSql = LoggedSqlCollector.stop();
Assert.assertTrue(loggedSql.size() > 1);
String lazyLoadSql = loggedSql.get(1);
// contains the foreign key back to the parent bean (t0.order_id)
Assert.assertTrue(lazyLoadSql.contains("select t0.order_id c0, t0.id"));
Assert.assertTrue(lazyLoadSql.contains("order by t0.order_id, t0.id, t0.order_qty, t0.cretime desc"));
}
private void checkWithBuiltInManyBasic() {
Query<Order> query = Ebean.find(Order.class).fetch("details");
query.findList();
String sql = query.getGeneratedSql();
Assert.assertTrue(sql.contains("order by t0.id, t1.id asc, t1.order_qty asc, t1.cretime desc"));
}
private void checkWithBuiltInMany() {
Query<Order> query = Ebean.find(Order.class).fetch("details").order().desc("customer.name");
@@ -0,0 +1,87 @@
package org.avaje.ebeantest;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
/**
* Helper that can collect the SQL that is logged via SLF4J.
* <p>
* Used {@link #start()} and {@link #stop()} to collect the logged messages that contain the
* executed SQL statements.
* <p>
* Internally this uses a Logback Appender to collect messages for org.avaje.ebean.SQL.
*/
public class LoggedSqlCollector {
private static BasicAppender basicAppender = new BasicAppender();
static {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
basicAppender.setContext(lc);
Logger logger = (Logger) LoggerFactory.getLogger("org.avaje.ebean.SQL");
logger.addAppender(basicAppender);
logger.setLevel(Level.TRACE);
logger.setAdditive(true);
}
/**
* Start collection of the logged SQL statements.
*/
public static List<String> start() {
return basicAppender.collectStart();
}
/**
* Stop collection of the logged SQL statements return the list of captured messages that contain
* the SQL.
*/
public static List<String> stop() {
return basicAppender.collectEnd();
}
private static class BasicAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
List<String> messages = new ArrayList<String>();
@Override
protected void append(ILoggingEvent eventObject) {
if (started) {
messages.add(eventObject.getMessage());
}
}
/**
* Start collection.
*/
List<String> collectStart() {
List<String> tempMessages = messages;
messages = new ArrayList<String>();
// set started flag
start();
return tempMessages;
}
/**
* End collection.
*/
List<String> collectEnd() {
// set stopped state
stop();
List<String> tempMessages = messages;
messages = new ArrayList<String>();
return tempMessages;
}
}
}