mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba5702211 | ||
|
|
2e7aeae004 | ||
|
|
3f2676ab49 | ||
|
|
3f29acb25c | ||
|
|
6d1a41f979 | ||
|
|
aee46955a7 | ||
|
|
38a93b9814 | ||
|
|
5f2ad0dc62 | ||
|
|
ece7f481bc | ||
|
|
fa4d0380e5 | ||
|
|
713ba4889d | ||
|
|
0543745e18 | ||
|
|
4e2bc6cce6 | ||
|
|
f2d422ff5a | ||
|
|
176197513d | ||
|
|
1e3035c558 | ||
|
|
17f7143447 | ||
|
|
394dfc96d1 | ||
|
|
452ce78c3d | ||
|
|
4cb13760c2 | ||
|
|
5cc2eff0d4 | ||
|
|
af9a01be77 | ||
|
|
cceb7c035c | ||
|
|
1ddc103582 | ||
|
|
b973cc3b86 | ||
|
|
10f0ea9bae | ||
|
|
c49dd54500 | ||
|
|
bf0944bb2a | ||
|
|
59ba6244c1 | ||
|
|
f88524b34c | ||
|
|
6838b4df4f | ||
|
|
5db7ae504e |
@@ -1,15 +1,12 @@
|
||||
[](https://waffle.io/ebean-orm/avaje-ebeanorm)
|
||||
avaje-ebeanorm
|
||||
==============
|
||||
- Release - 4.0.2 - May 19th: https://github.com/ebean-orm/avaje-ebeanorm/wiki/4.0.2-Release
|
||||
- Release - 4.0.3 and 4.0.4 contained some bug fixes plus the Model and Finder objects.
|
||||
|
||||
|
||||
Maven Dependency
|
||||
----------------
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.0.4</version>
|
||||
<version>4.1.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.1.0</version>
|
||||
<version>4.1.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
|
||||
@@ -475,7 +475,31 @@ public final class Ebean {
|
||||
public static void insert(Collection<?> beans) {
|
||||
serverMgr.getPrimaryServer().insert(beans);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated with the version
|
||||
* property updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Customer customer = Ebean.find(Customer, id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* Ebean.markAsDirty(customer);
|
||||
* Ebean.save(customer);
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public static void markAsDirty(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().markAsDirty(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
|
||||
* use this update() method rather than save().
|
||||
|
||||
@@ -837,6 +837,28 @@ public interface EbeanServer {
|
||||
*/
|
||||
public int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Customer customer = ebeanServer.find(Customer, id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* ebeanServer.markAsDirty(customer);
|
||||
* ebeanServer.save(customer);
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public void markAsDirty(Object bean);
|
||||
|
||||
/**
|
||||
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
|
||||
* use this update() method rather than save().
|
||||
|
||||
@@ -85,6 +85,30 @@ public abstract class Model {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Customer customer = Customer.find.byId(id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* customer.markAsDirty();
|
||||
* customer.save();
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
*
|
||||
|
||||
@@ -32,6 +32,8 @@ public class DataSourceConfig {
|
||||
|
||||
private int isolationLevel = Transaction.READ_COMMITTED;
|
||||
|
||||
private boolean autoCommit;
|
||||
|
||||
private String heartbeatSql;
|
||||
|
||||
private int heartbeatFreqSecs = 30;
|
||||
@@ -131,6 +133,20 @@ public class DataSourceConfig {
|
||||
public void setIsolationLevel(int isolationLevel) {
|
||||
this.isolationLevel = isolationLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return autoCommit setting.
|
||||
*/
|
||||
public boolean isAutoCommit() {
|
||||
return autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to turn on autoCommit.
|
||||
*/
|
||||
public void setAutoCommit(boolean autoCommit) {
|
||||
this.autoCommit = autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum number of connections the pool should maintain.
|
||||
@@ -450,6 +466,7 @@ public class DataSourceConfig {
|
||||
String dbUrl = properties.get(prefix + "databaseUrl", null);
|
||||
this.url = properties.get(prefix + "url", dbUrl);
|
||||
|
||||
this.autoCommit = properties.getBoolean(prefix + "autoCommit", false);
|
||||
this.captureStackTrace = properties.getBoolean(prefix + "captureStackTrace", false);
|
||||
this.maxStackTraceSize = properties.getInt(prefix + "maxStackTraceSize", 5);
|
||||
this.leakTimeMinutes = properties.getInt(prefix + "leakTimeMinutes", 30);
|
||||
|
||||
@@ -175,6 +175,13 @@ public class ServerConfig {
|
||||
*/
|
||||
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
|
||||
|
||||
/**
|
||||
* Set to true if the DataSource uses autoCommit.
|
||||
* <p>
|
||||
* Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
private boolean autoCommitMode;
|
||||
|
||||
/**
|
||||
* The data source JNDI name if using a JNDI DataSource.
|
||||
*/
|
||||
@@ -582,6 +589,20 @@ public class ServerConfig {
|
||||
public void setDataSourceJndiName(String dataSourceJndiName) {
|
||||
this.dataSourceJndiName = dataSourceJndiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on. This indicates to Ebean to use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
public boolean isAutoCommitMode() {
|
||||
return autoCommitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if autoCommit mode is on and Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
public void setAutoCommitMode(boolean autoCommitMode) {
|
||||
this.autoCommitMode = autoCommitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
@@ -1281,6 +1302,7 @@ public class ServerConfig {
|
||||
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", false);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", false);
|
||||
namingConvention = createNamingConvention(p);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
|
||||
|
||||
@@ -11,7 +11,7 @@ public class DbDdlSyntax {
|
||||
|
||||
private boolean inlinePrimaryKeyConstraint = false;
|
||||
|
||||
private boolean addOneToOneUniqueContraint = false;
|
||||
private boolean addOneToOneUniqueContraint = true;
|
||||
|
||||
private int maxConstraintNameLength = 32;
|
||||
|
||||
|
||||
@@ -53,13 +53,15 @@ public class ManyWhereJoins implements Serializable {
|
||||
String join = elProp.getElPrefix();
|
||||
BeanProperty p = elProp.getBeanProperty();
|
||||
if (p instanceof BeanPropertyAssocMany<?>){
|
||||
join = addManyToJoin(join, p.getName());
|
||||
join = addManyToJoin(join, p.getName());
|
||||
}
|
||||
if (join != null){
|
||||
addJoin(join);
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
addJoin(join+"."+secondaryTableJoinPrefix);
|
||||
if (p != null) {
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
addJoin(join+"."+secondaryTableJoinPrefix);
|
||||
}
|
||||
}
|
||||
addParentJoins(join);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
public interface SpiExpressionFactory extends ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory();//FilterExprPath prefix);
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory();
|
||||
|
||||
}
|
||||
|
||||
@@ -532,12 +532,24 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
* Return the index of the first row to return in the query.
|
||||
*/
|
||||
public int getFirstRow();
|
||||
|
||||
/**
|
||||
* Internally set by Ebean when this query must use the DISTINCT keyword.
|
||||
* <p>
|
||||
* This does not exclude/remove the use of the id property.
|
||||
*/
|
||||
public Query<T> setSqlDistinct(boolean sqlDistinct);
|
||||
|
||||
/**
|
||||
* return true if this query uses DISTINCT.
|
||||
* Return true if this query has been specified by a user or internally by Ebean to use DISTINCT.
|
||||
*/
|
||||
public boolean isDistinctQuery();
|
||||
|
||||
/**
|
||||
* Return true if this query has been specified by a user to use DISTINCT.
|
||||
*/
|
||||
public boolean isDistinct();
|
||||
|
||||
|
||||
/**
|
||||
* Set default select clauses where none have been explicitly defined.
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,11 @@ import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
*/
|
||||
public interface SpiTransaction extends Transaction {
|
||||
|
||||
/**
|
||||
* End the transaction when had query only use.
|
||||
*/
|
||||
public void endQueryOnly();
|
||||
|
||||
/**
|
||||
* Return the string prefix with the transactin id and label used in logging.
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,6 @@ public abstract class BeanRequest {
|
||||
|
||||
protected boolean createdTransaction;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.serverName = ebeanServer.getName();
|
||||
@@ -62,29 +60,19 @@ public abstract class BeanRequest {
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createServerTransaction(false, -1);
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
//if (readOnlyTransaction) {
|
||||
// readOnly = true;
|
||||
// transaction.setReadOnly(true);
|
||||
//}
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
if (readOnly) {
|
||||
transaction.rollback();
|
||||
} else {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
|
||||
@@ -1112,7 +1112,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// predicates on *ToMany properties
|
||||
if (query.initManyWhereJoins()) {
|
||||
// we need a sql distinct now
|
||||
query.setDistinct(true);
|
||||
query.setSqlDistinct(true);
|
||||
}
|
||||
|
||||
boolean allowOneManyFetch = true;
|
||||
@@ -1198,18 +1198,12 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
}
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(desc, spiQuery, t);
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (T) request.findId();
|
||||
|
||||
T bean = (T) request.findId();
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return bean;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,15 +1250,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Set<T> set = (Set<T>) request.findSet();
|
||||
return (Set<T>) request.findSet();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return set;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
// String stackTrace = throwablePrinter.print(ex);
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,15 +1269,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Map<?, T> map = (Map<?, T>) request.findMap();
|
||||
return (Map<?, T>) request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return map;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
// String stackTrace = throwablePrinter.print(ex);
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,14 +1287,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
int rowCount = request.findRowCount();
|
||||
return request.findRowCount();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return rowCount;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,14 +1306,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<Object> list = request.findIds();
|
||||
return request.findIds();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1434,10 +1410,8 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
} finally {
|
||||
// do nothing - findVisit garuntee's cleanup of the transaction if required
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1448,10 +1422,9 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIterate();
|
||||
// request.endTransIfRequired();
|
||||
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
request.endTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -1468,14 +1441,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<T> list = request.findList();
|
||||
return request.findList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1518,14 +1487,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<SqlRow> list = request.findList();
|
||||
return request.findList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1535,14 +1500,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Set<SqlRow> set = request.findSet();
|
||||
return request.findSet();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return set;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1551,14 +1512,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Map<?, SqlRow> map = request.findMap();
|
||||
return request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return map;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1576,6 +1533,16 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
persister.save(checkEntityBean(bean), t);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void markAsDirty(Object bean) {
|
||||
if (bean instanceof EntityBean == false) {
|
||||
throw new IllegalArgumentException("This bean is not an EntityBean?");
|
||||
}
|
||||
// mark the bean as dirty (so that an update will not get skipped)
|
||||
((EntityBean)bean)._ebean_getIntercept().setDirty(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the bean using the default 'updatesDeleteMissingChildren' setting.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -22,6 +24,7 @@ import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
@@ -31,6 +34,7 @@ import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
@@ -42,8 +46,6 @@ import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
@@ -113,8 +115,7 @@ public class InternalConfiguration {
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor,
|
||||
serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
this.transactionManager = createTransactionManager();
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
|
||||
|
||||
@@ -131,6 +132,34 @@ public class InternalConfiguration {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
private TransactionManager createTransactionManager() {
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on.
|
||||
*/
|
||||
private boolean isAutoCommitMode() {
|
||||
if (serverConfig.isAutoCommitMode()) {
|
||||
// explicitly set
|
||||
return true;
|
||||
}
|
||||
DataSource dataSource = serverConfig.getDataSource();
|
||||
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
|
||||
// We know the DataSourcePool is using autoCommit
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
|
||||
@@ -193,14 +193,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* It ends the query only transaction.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as readOnly transaction
|
||||
transaction.rollback();
|
||||
transaction.endQueryOnly();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
private List<BeanPropertyAssocMany<?>> updatedManys;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type) {
|
||||
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.entityBean = (EntityBean) bean;
|
||||
@@ -103,12 +103,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
this.bean = bean;
|
||||
this.parentBean = parentBean;
|
||||
this.controller = beanDescriptor.getPersistController();
|
||||
|
||||
if (PersistRequest.Type.DETERMINE != type) {
|
||||
this.type = type;
|
||||
} else {
|
||||
// determine mode during cascade save (supporting stateless update)
|
||||
this.type = beanDescriptor.isInsertMode(intercept) ? Type.INSERT : Type.UPDATE;
|
||||
this.type = type;
|
||||
|
||||
if (saveRecurse) {
|
||||
this.persistCascade = t.isPersistCascade();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,15 +40,6 @@ public final class RelationalQueryRequest {
|
||||
this.trans = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
@@ -58,10 +49,6 @@ public final class RelationalQueryRequest {
|
||||
if (trans == null || !trans.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = ebeanServer.createServerTransaction(false, -1);
|
||||
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
// trans.setReadOnly(true);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
@@ -72,8 +59,7 @@ public final class RelationalQueryRequest {
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as a readOnly transaction.
|
||||
trans.rollback();
|
||||
trans.endQueryOnly();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ public interface SpiOrmQueryRequest<T> {
|
||||
*/
|
||||
public void endTransIfRequired();
|
||||
|
||||
public void rollbackTransIfRequired();
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,8 @@ public class CreateTableColumnVisitor extends BaseTablePropertyVisitor {
|
||||
|
||||
private final CreateTableVisitor parent;
|
||||
|
||||
private BeanPropertyAssocOne<?> embedded;
|
||||
|
||||
public CreateTableColumnVisitor(CreateTableVisitor parent, DdlGenContext ctx) {
|
||||
this.parent = parent;
|
||||
this.ctx = ctx;
|
||||
@@ -68,6 +70,7 @@ public class CreateTableColumnVisitor extends BaseTablePropertyVisitor {
|
||||
@Override
|
||||
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
|
||||
|
||||
this.embedded = embedded;
|
||||
visitScalar(p);
|
||||
}
|
||||
|
||||
@@ -184,7 +187,12 @@ public class CreateTableColumnVisitor extends BaseTablePropertyVisitor {
|
||||
|
||||
private String createUniqueConstraint(BeanProperty p) {
|
||||
|
||||
StringBuilder expr = createUniqueConstraintBuffer(p.getBeanDescriptor().getBaseTable(), p.getDbColumn());
|
||||
String baseTable = p.getBeanDescriptor().getBaseTable();
|
||||
if (baseTable == null) {
|
||||
// Embedded bean property that has unique constraint on it
|
||||
baseTable = embedded.getBeanDescriptor().getBaseTable();
|
||||
}
|
||||
StringBuilder expr = createUniqueConstraintBuffer(baseTable, p.getDbColumn());
|
||||
|
||||
expr.append(p.getDbColumn()).append(")");
|
||||
return expr.toString();
|
||||
|
||||
@@ -1531,7 +1531,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
if (propertyDeploy && chain != null) {
|
||||
BeanFkeyProperty fk = fkeyMap.get(propName);
|
||||
if (fk != null) {
|
||||
return fk.create(chain.getExpression());
|
||||
return fk.create(chain.getExpression(), chain.isContainsMany());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1886,21 +1886,31 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
public boolean isInsertMode(EntityBeanIntercept ebi) {
|
||||
/**
|
||||
* Return true if this bean should be inserted rather than updated.
|
||||
*
|
||||
* @param ebi
|
||||
* The entity bean intercept
|
||||
* @param insertMode
|
||||
* true if the 'root request' was an insert rather than an update
|
||||
*/
|
||||
public boolean isInsertMode(EntityBeanIntercept ebi, boolean insertMode) {
|
||||
|
||||
if (ebi.isLoaded()) {
|
||||
// must be an update as the bean is loaded
|
||||
return false;
|
||||
}
|
||||
|
||||
// determine based on Id property
|
||||
if (idProperty.isEmbedded()) {
|
||||
// not using Id generator so just base on isLoaded()
|
||||
return !ebi.isLoaded();
|
||||
}
|
||||
//if (idGenerator == null) {
|
||||
// return !ebi.isLoaded();
|
||||
//} else {
|
||||
return !hasIdProperty(ebi);
|
||||
//}
|
||||
if (!hasIdProperty(ebi)) {
|
||||
// No Id property means it must be an insert
|
||||
return true;
|
||||
}
|
||||
// same as the 'root request'
|
||||
return insertMode;
|
||||
}
|
||||
|
||||
public boolean isReference(EntityBeanIntercept ebi) {
|
||||
|
||||
@@ -877,7 +877,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
if (!tableJoin.hasJoinColumns()) {
|
||||
// define Join as the inverse of the mappedBy property
|
||||
DeployTableJoin otherTableJoin = mappedAssocOne.getTableJoin();
|
||||
otherTableJoin.copyTo(tableJoin, true, tableJoin.getTable());
|
||||
otherTableJoin.copyWithoutType(tableJoin, true, tableJoin.getTable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1019,6 +1019,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// set bean controller, finder and listener
|
||||
setBeanControllerFinderListener(desc);
|
||||
deplyInherit.process(desc);
|
||||
desc.checkInheritanceMapping();
|
||||
|
||||
createProperties.createProperties(desc);
|
||||
|
||||
|
||||
@@ -10,182 +10,188 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
*/
|
||||
public final class BeanFkeyProperty implements ElPropertyValue {
|
||||
|
||||
private final String placeHolder;
|
||||
private final String prefix;
|
||||
private final String name;
|
||||
private final String dbColumn;
|
||||
private final String placeHolder;
|
||||
private final String prefix;
|
||||
private final String name;
|
||||
private final String dbColumn;
|
||||
private final boolean containsMany;
|
||||
|
||||
private int deployOrder;
|
||||
private int deployOrder;
|
||||
|
||||
public BeanFkeyProperty(String prefix, String name, String dbColumn, int deployOrder) {
|
||||
this.prefix = prefix;
|
||||
this.name = name;
|
||||
this.dbColumn = dbColumn;
|
||||
this.deployOrder = deployOrder;
|
||||
this.placeHolder = calcPlaceHolder(prefix, dbColumn);
|
||||
}
|
||||
public BeanFkeyProperty(String prefix, String name, String dbColumn, int deployOrder) {
|
||||
this(prefix, name, dbColumn, deployOrder, false);
|
||||
}
|
||||
|
||||
private BeanFkeyProperty(String prefix, String name, String dbColumn, int deployOrder, boolean containsMany) {
|
||||
this.prefix = prefix;
|
||||
this.name = name;
|
||||
this.dbColumn = dbColumn;
|
||||
this.deployOrder = deployOrder;
|
||||
this.containsMany = containsMany;
|
||||
this.placeHolder = calcPlaceHolder(prefix, dbColumn);
|
||||
}
|
||||
|
||||
public int getDeployOrder() {
|
||||
return deployOrder;
|
||||
}
|
||||
public int getDeployOrder() {
|
||||
return deployOrder;
|
||||
}
|
||||
|
||||
private String calcPlaceHolder(String prefix, String dbColumn) {
|
||||
if (prefix != null) {
|
||||
return "${" + prefix + "}" + dbColumn;
|
||||
} else {
|
||||
return ROOT_ELPREFIX + dbColumn;
|
||||
}
|
||||
private String calcPlaceHolder(String prefix, String dbColumn) {
|
||||
if (prefix != null) {
|
||||
return "${" + prefix + "}" + dbColumn;
|
||||
} else {
|
||||
return ROOT_ELPREFIX + dbColumn;
|
||||
}
|
||||
}
|
||||
|
||||
public BeanFkeyProperty create(String expression) {
|
||||
int len = expression.length() - name.length() - 1;
|
||||
String prefix = expression.substring(0, len);
|
||||
public BeanFkeyProperty create(String expression, boolean containsMany) {
|
||||
int len = expression.length() - name.length() - 1;
|
||||
String prefix = expression.substring(0, len);
|
||||
|
||||
return new BeanFkeyProperty(prefix, name, dbColumn, deployOrder);
|
||||
}
|
||||
return new BeanFkeyProperty(prefix, name, dbColumn, deployOrder, containsMany);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false for keys.
|
||||
*/
|
||||
public boolean isDbEncrypted() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns false for keys.
|
||||
*/
|
||||
public boolean isDbEncrypted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false for keys.
|
||||
*/
|
||||
public boolean isLocalEncrypted() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns false for keys.
|
||||
*/
|
||||
public boolean isLocalEncrypted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only usable as ElPropertyDeploy.
|
||||
*/
|
||||
public boolean isDeployOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsFormulaWithJoin() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Only usable as ElPropertyDeploy.
|
||||
*/
|
||||
public boolean isDeployOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*/
|
||||
public boolean containsMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsManySince(String sinceProperty) {
|
||||
return containsMany();
|
||||
}
|
||||
@Override
|
||||
public boolean containsFormulaWithJoin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
/**
|
||||
* Returns false.
|
||||
*/
|
||||
public boolean containsMany() {
|
||||
return containsMany;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public boolean containsManySince(String sinceProperty) {
|
||||
return containsMany();
|
||||
}
|
||||
|
||||
public String getElName() {
|
||||
return name;
|
||||
}
|
||||
public String getDbColumn() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public Object[] getAssocOneIdValues(EntityBean value) {
|
||||
return null;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
return null;
|
||||
}
|
||||
public String getElName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public Object[] getAssocOneIdValues(EntityBean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocIdInValueExpr(int size) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false as not an AssocOne.
|
||||
*/
|
||||
public boolean isAssocId() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAssocProperty() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getElPlaceholder(boolean encrypted) {
|
||||
return placeHolder;
|
||||
}
|
||||
/**
|
||||
* Returns null as not an AssocOne.
|
||||
*/
|
||||
public String getAssocIdInValueExpr(int size) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getElPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
/**
|
||||
* Returns false as not an AssocOne.
|
||||
*/
|
||||
public boolean isAssocId() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getJdbcType() {
|
||||
return 0;
|
||||
}
|
||||
public boolean isAssocProperty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object parseDateTime(long systemTimeMillis) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public String getElPlaceholder(boolean encrypted) {
|
||||
return placeHolder;
|
||||
}
|
||||
|
||||
public StringFormatter getStringFormatter() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public String getElPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public StringParser getStringParser() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void elSetReference(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public int getJdbcType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Object elConvertType(Object value) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public BeanProperty getBeanProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public Object parseDateTime(long systemTimeMillis) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public StringFormatter getStringFormatter() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public StringParser getStringParser() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public BeanProperty getBeanProperty() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public void elSetReference(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public String getDeployProperty() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
public Object elConvertType(Object value) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public void elSetValue(EntityBean bean, Object value, boolean populate) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetValue(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public Object elGetReference(EntityBean bean) {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
public String getDeployProperty() {
|
||||
throw new RuntimeException("ElPropertyDeploy only - not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -153,8 +153,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
// these fkcolumns always on base table hence t0 as alias
|
||||
sb.append("t0.").append(exportedProperties[i].getForeignDbColumn());
|
||||
// these fk columns are either on the intersection (int_) or base table (t0)
|
||||
String fkTableAlias = isManyToMany() ? "int_" : "t0";
|
||||
sb.append(fkTableAlias).append(".").append(exportedProperties[i].getForeignDbColumn());
|
||||
}
|
||||
if (fetchOrderBy != null) {
|
||||
sb.append(", ").append(fetchOrderBy);
|
||||
|
||||
+7
-11
@@ -1,19 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
public class BeanPropertySimpleCollection<T> extends BeanPropertyAssocMany<T> {
|
||||
|
||||
private final ScalarType<T> collectionScalarType;
|
||||
|
||||
public BeanPropertySimpleCollection(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertySimpleCollection<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
this.collectionScalarType = deploy.getCollectionScalarType();
|
||||
}
|
||||
public BeanPropertySimpleCollection(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertySimpleCollection<T> deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
super.initialise();
|
||||
}
|
||||
|
||||
public void initialise() {
|
||||
super.initialise();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,6 @@ import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
*/
|
||||
public final class TableJoin {
|
||||
|
||||
public static final String LEFT_OUTER = "left outer join";
|
||||
|
||||
public static final String JOIN = "join";
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for
|
||||
* intersection tables (ManyToMany).
|
||||
|
||||
@@ -13,18 +13,17 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.IntersectionRow;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
import com.avaje.ebeaninternal.server.persist.dmlbind.BindableRequest;
|
||||
import com.avaje.ebeaninternal.util.ValueUtil;
|
||||
|
||||
/**
|
||||
* Imported Embedded id.
|
||||
*/
|
||||
public class ImportedIdEmbedded implements ImportedId {
|
||||
|
||||
final BeanPropertyAssoc<?> owner;
|
||||
private final BeanPropertyAssoc<?> owner;
|
||||
|
||||
final BeanPropertyAssocOne<?> foreignAssocOne;
|
||||
private final BeanPropertyAssocOne<?> foreignAssocOne;
|
||||
|
||||
final ImportedIdSimple[] imported;
|
||||
private final ImportedIdSimple[] imported;
|
||||
|
||||
public ImportedIdEmbedded(BeanPropertyAssoc<?> owner, BeanPropertyAssocOne<?> foreignAssocOne, ImportedIdSimple[] imported) {
|
||||
this.owner = owner;
|
||||
|
||||
@@ -13,6 +13,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -905,4 +908,32 @@ public class DeployBeanDescriptor<T> {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the mapping for class inheritance
|
||||
*/
|
||||
public void checkInheritanceMapping() {
|
||||
if (inheritInfo == null) {
|
||||
checkInheritance(getBeanType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check valid mapping annotations on the class hierarchy.
|
||||
*/
|
||||
private void checkInheritance(Class<?> beanType) {
|
||||
|
||||
Class<?> parent = beanType.getSuperclass();
|
||||
if (parent == null || Object.class.equals(parent)) {
|
||||
// all good
|
||||
return;
|
||||
}
|
||||
if (parent.isAnnotationPresent(Entity.class)) {
|
||||
String msg = "Checking "+getBeanType()+" and found "+parent+" that has @Entity annotation rather than MappedSuperclass?";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (parent.isAnnotationPresent(MappedSuperclass.class)) {
|
||||
// continue checking
|
||||
checkInheritance(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-30
@@ -2,40 +2,28 @@ package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
public class DeployBeanPropertySimpleCollection<T> extends DeployBeanPropertyAssocMany<T> {
|
||||
|
||||
private final ScalarType<T> collectionScalarType;
|
||||
|
||||
public DeployBeanPropertySimpleCollection(DeployBeanDescriptor<?> desc, Class<T> targetType, ScalarType<T> scalarType, ManyType manyType) {
|
||||
super(desc, targetType, manyType);
|
||||
this.collectionScalarType = scalarType;
|
||||
this.modifyListenMode = ModifyListenMode.ALL;
|
||||
}
|
||||
public DeployBeanPropertySimpleCollection(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
|
||||
super(desc, targetType, manyType);
|
||||
this.modifyListenMode = ModifyListenMode.ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scalarType of the collection elements.
|
||||
*/
|
||||
public ScalarType<T> getCollectionScalarType() {
|
||||
return collectionScalarType;
|
||||
}
|
||||
/**
|
||||
* Returns false as never a ManyToMany.
|
||||
*/
|
||||
@Override
|
||||
public boolean isManyToMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false as never a ManyToMany.
|
||||
*/
|
||||
@Override
|
||||
public boolean isManyToMany() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns true as always Unidirectional.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUnidirectional() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true as always Unidirectional.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUnidirectional() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
@@ -19,205 +17,196 @@ import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
*/
|
||||
public class DeployTableJoin {
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key.
|
||||
* This occurs for intersection tables (ManyToMany).
|
||||
*/
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* The type of join. LEFT OUTER etc.
|
||||
*/
|
||||
private SqlJoinType type = SqlJoinType.INNER;
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* The list of properties mapped to this joined table.
|
||||
*/
|
||||
private ArrayList<DeployBeanProperty> properties = new ArrayList<DeployBeanProperty>();
|
||||
/**
|
||||
* The joined table.
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* The list of join column pairs. Used to generate the on clause.
|
||||
*/
|
||||
private ArrayList<DeployTableJoinColumn> columns = new ArrayList<DeployTableJoinColumn>();
|
||||
/**
|
||||
* The type of join. LEFT OUTER etc.
|
||||
*/
|
||||
private SqlJoinType type = SqlJoinType.INNER;
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
private InheritInfo inheritInfo;
|
||||
/**
|
||||
* The list of properties mapped to this joined table.
|
||||
*/
|
||||
private ArrayList<DeployBeanProperty> properties = new ArrayList<DeployBeanProperty>();
|
||||
|
||||
/**
|
||||
* Create a DeployTableJoin.
|
||||
*/
|
||||
public DeployTableJoin() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type + " " + table + " " + columns;
|
||||
/**
|
||||
* The list of join column pairs. Used to generate the on clause.
|
||||
*/
|
||||
private ArrayList<DeployTableJoinColumn> columns = new ArrayList<DeployTableJoinColumn>(4);
|
||||
|
||||
/**
|
||||
* The persist cascade info.
|
||||
*/
|
||||
private BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
|
||||
|
||||
private InheritInfo inheritInfo;
|
||||
|
||||
/**
|
||||
* Create a DeployTableJoin.
|
||||
*/
|
||||
public DeployTableJoin() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type + " " + table + " " + columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key. This occurs for intersection tables
|
||||
* (ManyToMany).
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the JoinOnPair have been set.
|
||||
*/
|
||||
public boolean hasJoinColumns() {
|
||||
return columns.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the columns to this join potentially reversing the columns.
|
||||
*/
|
||||
public void setColumns(DeployTableJoinColumn[] cols, boolean reverse) {
|
||||
columns = new ArrayList<DeployTableJoinColumn>();
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
addJoinColumn(cols[i].copy(reverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the imported foreign key maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
/**
|
||||
* Add a join pair
|
||||
*/
|
||||
public void addJoinColumn(DeployTableJoinColumn pair) {
|
||||
columns.add(pair);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag set when the imported key maps to the primary key.
|
||||
* This occurs for intersection tables (ManyToMany).
|
||||
*/
|
||||
public void setImportedPrimaryKey(boolean importedPrimaryKey) {
|
||||
this.importedPrimaryKey = importedPrimaryKey;
|
||||
}
|
||||
/**
|
||||
* Add a JoinColumn
|
||||
* <p>
|
||||
* The order is generally true for OneToMany and false for ManyToOne relationships.
|
||||
* </p>
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
if (!"".equals(jc.table())) {
|
||||
setTable(jc.table());
|
||||
}
|
||||
if (!"".equals(jc.name()) || !"".equals(jc.referencedColumnName())) {
|
||||
// only add the join column details when name or referencedColumnName is specified
|
||||
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the JoinOnPair have been set.
|
||||
*/
|
||||
public boolean hasJoinColumns() {
|
||||
return columns.size() > 0;
|
||||
/**
|
||||
* Add a JoinColumn array.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
for (int i = 0; i < jcArray.length; i++) {
|
||||
addJoinColumn(order, jcArray[i], beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persist info.
|
||||
*/
|
||||
public BeanCascadeInfo getCascadeInfo() {
|
||||
return cascadeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public DeployTableJoinColumn[] columns() {
|
||||
return (DeployTableJoinColumn[]) columns.toArray(new DeployTableJoinColumn[columns.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all the columns to this join potentially reversing the columns.
|
||||
*/
|
||||
public void setColumns(DeployTableJoinColumn[] cols, boolean reverse) {
|
||||
columns = new ArrayList<DeployTableJoinColumn>();
|
||||
for (int i = 0; i < cols.length; i++) {
|
||||
addJoinColumn(cols[i].copy(reverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a join pair
|
||||
*/
|
||||
public void addJoinColumn(DeployTableJoinColumn pair) {
|
||||
columns.add(pair);
|
||||
}
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public DeployBeanProperty[] properties() {
|
||||
return (DeployBeanProperty[]) properties.toArray(new DeployBeanProperty[properties.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn
|
||||
* <p>
|
||||
* The order is generally true for OneToMany and false for ManyToOne relationships.
|
||||
* </p>
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
|
||||
if (!"".equals(jc.table())) {
|
||||
setTable(jc.table());
|
||||
}
|
||||
addJoinColumn(new DeployTableJoinColumn(order, jc, beanTable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a JoinColumn array.
|
||||
*/
|
||||
public void addJoinColumn(boolean order, JoinColumn[] jcArray, BeanTable beanTable) {
|
||||
for (int i = 0; i < jcArray.length; i++) {
|
||||
addJoinColumn(order, jcArray[i], beanTable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the join columns.
|
||||
*/
|
||||
public DeployTableJoinColumn[] columns() {
|
||||
return (DeployTableJoinColumn[])columns.toArray(new DeployTableJoinColumn[columns.size()]);
|
||||
}
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For secondary table joins returns the properties mapped to that table.
|
||||
*/
|
||||
public DeployBeanProperty[] properties() {
|
||||
return (DeployBeanProperty[])properties.toArray(new DeployBeanProperty[properties.size()]);
|
||||
}
|
||||
/**
|
||||
* set the joined table name.
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the joined table name.
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the joined table name.
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of join. LEFT OUTER JOIN etc.
|
||||
*/
|
||||
public SqlJoinType getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(SqlJoinType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this join is a left outer join.
|
||||
*/
|
||||
public boolean isOuterJoin() {
|
||||
return type == SqlJoinType.OUTER;
|
||||
}
|
||||
|
||||
private void setType(SqlJoinType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of join.
|
||||
*/
|
||||
public void setType(String joinType) {
|
||||
joinType = joinType.toUpperCase();
|
||||
if (joinType.equalsIgnoreCase(TableJoin.JOIN)) {
|
||||
type = SqlJoinType.INNER;
|
||||
} else if (joinType.indexOf("LEFT") > -1) {
|
||||
type = SqlJoinType.OUTER;
|
||||
} else if (joinType.indexOf("OUTER") > -1) {
|
||||
type = SqlJoinType.OUTER;
|
||||
} else if (joinType.indexOf("INNER") > -1) {
|
||||
type = SqlJoinType.INNER;
|
||||
} else {
|
||||
throw new RuntimeException(Message.msg("join.type.unknown", joinType));
|
||||
}
|
||||
}
|
||||
|
||||
public DeployTableJoin createInverse(String tableName) {
|
||||
|
||||
DeployTableJoin inverse = new DeployTableJoin();
|
||||
public DeployTableJoin createInverse(String tableName) {
|
||||
|
||||
return copyTo(inverse, true, tableName);
|
||||
DeployTableJoin inverse = new DeployTableJoin();
|
||||
return copyInternal(inverse, true, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyTo(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, true);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyWithoutType(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
return copyInternal(destJoin, reverse, tableName, false);
|
||||
}
|
||||
|
||||
private DeployTableJoin copyInternal(DeployTableJoin destJoin, boolean reverse, String tableName, boolean withType) {
|
||||
|
||||
destJoin.setTable(tableName);
|
||||
if (withType) {
|
||||
destJoin.setType(type);
|
||||
}
|
||||
|
||||
public DeployTableJoin copyTo(DeployTableJoin destJoin, boolean reverse, String tableName) {
|
||||
|
||||
destJoin.setTable(tableName);
|
||||
destJoin.setType(type);
|
||||
destJoin.setColumns(columns(), reverse);
|
||||
|
||||
return destJoin;
|
||||
}
|
||||
destJoin.setColumns(columns(), reverse);
|
||||
|
||||
public InheritInfo getInheritInfo() {
|
||||
return inheritInfo;
|
||||
}
|
||||
return destJoin;
|
||||
}
|
||||
|
||||
public void setInheritInfo(InheritInfo inheritInfo) {
|
||||
this.inheritInfo = inheritInfo;
|
||||
}
|
||||
public InheritInfo getInheritInfo() {
|
||||
return inheritInfo;
|
||||
}
|
||||
|
||||
public void setInheritInfo(InheritInfo inheritInfo) {
|
||||
this.inheritInfo = inheritInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ import com.avaje.ebean.config.TableName;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
@@ -160,7 +160,7 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
destJoin.addJoinColumn(false, joinTable.inverseJoinColumns(), prop.getBeanTable());
|
||||
|
||||
intJoin.setType(TableJoin.LEFT_OUTER);
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
|
||||
// reverse join from dest back to intersection
|
||||
DeployTableJoin inverseDest = destJoin.createInverse(intTableName);
|
||||
@@ -216,7 +216,7 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
intTableName = getM2MJoinTableName(localTable, otherTable);
|
||||
|
||||
intJoin.setTable(intTableName);
|
||||
intJoin.setType(TableJoin.LEFT_OUTER);
|
||||
intJoin.setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
DeployTableJoin destJoin = prop.getTableJoin();
|
||||
@@ -282,7 +282,7 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
manyProp.setManyToMany(true);
|
||||
manyProp.setModifyListenMode(ModifyListenMode.ALL);
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(TableJoin.LEFT_OUTER);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
@@ -307,7 +307,7 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
|
||||
manyProp.setBeanTable(assoc);
|
||||
manyProp.getTableJoin().setType(TableJoin.LEFT_OUTER);
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ import com.avaje.ebean.annotation.Where;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for Associated One beans.
|
||||
@@ -99,7 +99,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
if (notNull != null) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(TableJoin.JOIN);
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,34 +9,33 @@ import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta;
|
||||
*/
|
||||
public class AnnotationSql extends AnnotationParser {
|
||||
|
||||
public AnnotationSql(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
public AnnotationSql(DeployBeanInfo<?> info) {
|
||||
super(info);
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
Sql sql = cls.getAnnotation(Sql.class);
|
||||
if (sql != null){
|
||||
setSql(sql);
|
||||
}
|
||||
|
||||
|
||||
SqlSelect sqlSelect = cls.getAnnotation(SqlSelect.class);
|
||||
if (sqlSelect != null){
|
||||
setSqlSelect(sqlSelect);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSql(Sql sql) {
|
||||
SqlSelect[] select = sql.select();
|
||||
for (int i = 0; i < select.length; i++) {
|
||||
setSqlSelect(select[i]);
|
||||
}
|
||||
}
|
||||
public void parse() {
|
||||
Class<?> cls = descriptor.getBeanType();
|
||||
Sql sql = cls.getAnnotation(Sql.class);
|
||||
if (sql != null) {
|
||||
setSql(sql);
|
||||
}
|
||||
|
||||
private void setSqlSelect(SqlSelect sqlSelect) {
|
||||
SqlSelect sqlSelect = cls.getAnnotation(SqlSelect.class);
|
||||
if (sqlSelect != null) {
|
||||
setSqlSelect(sqlSelect);
|
||||
}
|
||||
}
|
||||
|
||||
DRawSqlMeta rawSqlMeta = new DRawSqlMeta(sqlSelect);
|
||||
descriptor.add(rawSqlMeta);
|
||||
}
|
||||
private void setSql(Sql sql) {
|
||||
SqlSelect[] select = sql.select();
|
||||
for (int i = 0; i < select.length; i++) {
|
||||
setSqlSelect(select[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSqlSelect(SqlSelect sqlSelect) {
|
||||
|
||||
DRawSqlMeta rawSqlMeta = new DRawSqlMeta(sqlSelect);
|
||||
descriptor.add(rawSqlMeta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
/**
|
||||
* Wraps information about a bean during deployment parsing.
|
||||
@@ -58,7 +58,7 @@ public class DeployBeanInfo<T> {
|
||||
if (tableJoin == null) {
|
||||
tableJoin = new DeployTableJoin();
|
||||
tableJoin.setTable(tableName);
|
||||
tableJoin.setType(TableJoin.JOIN);
|
||||
tableJoin.setType(SqlJoinType.INNER);
|
||||
descriptor.addTableJoin(tableJoin);
|
||||
|
||||
tableJoinMap.put(key, tableJoin);
|
||||
@@ -71,13 +71,8 @@ public class DeployBeanInfo<T> {
|
||||
*/
|
||||
public void setBeanJoinType(DeployBeanPropertyAssocOne<?> beanProp, boolean outerJoin) {
|
||||
|
||||
String joinType = TableJoin.JOIN;
|
||||
if (outerJoin){// && util.isUseOneToOneOptional()) {
|
||||
joinType = TableJoin.LEFT_OUTER;
|
||||
}
|
||||
|
||||
DeployTableJoin tableJoin = beanProp.getTableJoin();
|
||||
tableJoin.setType(joinType);
|
||||
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -264,7 +264,7 @@ public class DeployCreateProperties {
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(targetType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, scalarType, manyType);
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
|
||||
@@ -176,7 +176,7 @@ public class DataSourcePool implements DataSource {
|
||||
this.name = name;
|
||||
this.poolListener = createPoolListener(params.getPoolListener());
|
||||
|
||||
this.autoCommit = false;
|
||||
this.autoCommit = params.isAutoCommit();
|
||||
this.transactionIsolation = params.getIsolationLevel();
|
||||
|
||||
this.maxInactiveMillis = 1000 * params.getMaxInactiveTimeSecs();
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.avaje.ebeaninternal.server.core.PersistRequestOrmUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql;
|
||||
import com.avaje.ebeaninternal.server.core.Persister;
|
||||
import com.avaje.ebeaninternal.server.core.PstmtBatch;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest.Type;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanCollectionUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
@@ -172,7 +173,7 @@ public final class DefaultPersister implements Persister {
|
||||
if (req.isReference()) {
|
||||
// its a reference so see if there are manys to save...
|
||||
if (req.isPersistCascade()) {
|
||||
saveAssocMany(false, req);
|
||||
saveAssocMany(false, req, false);
|
||||
}
|
||||
req.checkUpdatedManysOnly();
|
||||
|
||||
@@ -218,16 +219,16 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
}
|
||||
|
||||
private void saveRecurse(EntityBean bean, Transaction t, Object parentBean) {
|
||||
private void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode) {
|
||||
|
||||
// determine insert or update taking into account stateless updates
|
||||
PersistRequestBean<?> request = createRequest(bean, t, parentBean, PersistRequest.Type.DETERMINE);
|
||||
PersistRequestBean<?> request = createRequest(bean, t, parentBean, insertMode);
|
||||
|
||||
if (request.isReference()) {
|
||||
// its a reference...
|
||||
if (request.isPersistCascade()) {
|
||||
// save any associated List held beans
|
||||
saveAssocMany(false, request);
|
||||
saveAssocMany(false, request, insertMode);
|
||||
}
|
||||
request.checkUpdatedManysOnly();
|
||||
|
||||
@@ -253,7 +254,7 @@ public final class DefaultPersister implements Persister {
|
||||
try {
|
||||
if (request.isPersistCascade()) {
|
||||
// save associated One beans recursively first
|
||||
saveAssocOne(request);
|
||||
saveAssocOne(request, true);
|
||||
}
|
||||
|
||||
// set the IDGenerated value if required
|
||||
@@ -262,7 +263,7 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
if (request.isPersistCascade()) {
|
||||
// save any associated List held beans
|
||||
saveAssocMany(true, request);
|
||||
saveAssocMany(true, request, true);
|
||||
}
|
||||
} finally {
|
||||
request.unRegisterBean();
|
||||
@@ -282,7 +283,7 @@ public final class DefaultPersister implements Persister {
|
||||
try {
|
||||
if (request.isPersistCascade()) {
|
||||
// save associated One beans recursively first
|
||||
saveAssocOne(request);
|
||||
saveAssocOne(request, false);
|
||||
}
|
||||
|
||||
if (request.isDirty()) {
|
||||
@@ -297,7 +298,7 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
if (request.isPersistCascade()) {
|
||||
// save all the beans in assocMany's after
|
||||
saveAssocMany(false, request);
|
||||
saveAssocMany(false, request, false);
|
||||
}
|
||||
|
||||
request.checkUpdatedManysOnly();
|
||||
@@ -539,7 +540,7 @@ public final class DefaultPersister implements Persister {
|
||||
* bean to the child beans.
|
||||
* </p>
|
||||
*/
|
||||
private void saveAssocMany(boolean insertedParent, PersistRequestBean<?> request) {
|
||||
private void saveAssocMany(boolean insertedParent, PersistRequestBean<?> request, boolean insertMode) {
|
||||
|
||||
EntityBean parentBean = request.getEntityBean();
|
||||
BeanDescriptor<?> desc = request.getBeanDescriptor();
|
||||
@@ -559,7 +560,7 @@ public final class DefaultPersister implements Persister {
|
||||
} else {
|
||||
t.depth(+1);
|
||||
prop.setParentBeanToChild(parentBean, detailBean);
|
||||
saveRecurse(detailBean, t, parentBean);
|
||||
saveRecurse(detailBean, t, parentBean, insertMode);
|
||||
t.depth(-1);
|
||||
}
|
||||
}
|
||||
@@ -571,7 +572,7 @@ public final class DefaultPersister implements Persister {
|
||||
for (int i = 0; i < manys.length; i++) {
|
||||
// check that property is loaded and not empty uninitialised collection
|
||||
if (request.isLoadedProperty(manys[i]) && !manys[i].isEmptyBeanCollection(parentBean)) {
|
||||
saveMany(new SaveManyPropRequest(insertedParent, manys[i], parentBean, request));
|
||||
saveMany(new SaveManyPropRequest(insertedParent, manys[i], parentBean, request), insertMode);
|
||||
if (!insertedParent) {
|
||||
request.addUpdatedManyProperty(manys[i]);
|
||||
}
|
||||
@@ -646,7 +647,7 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
}
|
||||
|
||||
private void saveMany(SaveManyPropRequest saveMany) {
|
||||
private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) {
|
||||
|
||||
if (saveMany.getMany().isManyToMany()) {
|
||||
|
||||
@@ -654,7 +655,7 @@ public final class DefaultPersister implements Persister {
|
||||
boolean saveIntersectionFromThisDirection = saveMany.isSaveIntersection();
|
||||
if (saveMany.isCascade()) {
|
||||
// Need explicit Cascade to save the beans on other side
|
||||
saveAssocManyDetails(saveMany, false);
|
||||
saveAssocManyDetails(saveMany, false, insertMode);
|
||||
}
|
||||
// for ManyToMany save the 'relationship' via inserts/deletes
|
||||
// into/from the intersection table
|
||||
@@ -670,7 +671,7 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
if (saveMany.isCascade()) {
|
||||
// potentially deletes 'missing children' for 'stateless update'
|
||||
saveAssocManyDetails(saveMany, saveMany.isDeleteMissingChildren());
|
||||
saveAssocManyDetails(saveMany, saveMany.isDeleteMissingChildren(), insertMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,7 +709,7 @@ public final class DefaultPersister implements Persister {
|
||||
/**
|
||||
* Save the details from a OneToMany collection.
|
||||
*/
|
||||
private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren) {
|
||||
private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren, boolean insertMode) {
|
||||
|
||||
BeanPropertyAssocMany<?> prop = saveMany.getMany();
|
||||
|
||||
@@ -791,7 +792,7 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
} else {
|
||||
// normal save recurse
|
||||
saveRecurse(detail, t, parentBean);
|
||||
saveRecurse(detail, t, parentBean, insertMode);
|
||||
}
|
||||
if (detailIds != null) {
|
||||
// remember the Id (other details not in the collection) will be removed
|
||||
@@ -839,7 +840,7 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
BeanPropertyAssocMany<?> manyProp = (BeanPropertyAssocMany<?>) prop;
|
||||
saveMany(new SaveManyPropRequest(manyProp, parentBean, (SpiTransaction) t));
|
||||
saveMany(new SaveManyPropRequest(manyProp, parentBean, (SpiTransaction) t), true);
|
||||
|
||||
} else if (prop instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> oneProp = (BeanPropertyAssocOne<?>) prop;
|
||||
@@ -849,7 +850,7 @@ public final class DefaultPersister implements Persister {
|
||||
int revertDepth = -1 * depth;
|
||||
|
||||
trans.depth(depth);
|
||||
saveRecurse(assocBean, t, parentBean);
|
||||
saveRecurse(assocBean, t, parentBean, true);
|
||||
trans.depth(revertDepth);
|
||||
|
||||
} else {
|
||||
@@ -1087,7 +1088,7 @@ public final class DefaultPersister implements Persister {
|
||||
/**
|
||||
* Save any associated one beans.
|
||||
*/
|
||||
private void saveAssocOne(PersistRequestBean<?> request) {
|
||||
private void saveAssocOne(PersistRequestBean<?> request, boolean insertMode) {
|
||||
|
||||
BeanDescriptor<?> desc = request.getBeanDescriptor();
|
||||
|
||||
@@ -1111,7 +1112,7 @@ public final class DefaultPersister implements Persister {
|
||||
} else {
|
||||
SpiTransaction t = request.getTransaction();
|
||||
t.depth(-1);
|
||||
saveRecurse(detailBean, t, null);
|
||||
saveRecurse(detailBean, t, null, insertMode);
|
||||
t.depth(+1);
|
||||
}
|
||||
}
|
||||
@@ -1196,38 +1197,52 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create the Persist Request Object that wraps all the objects used to
|
||||
* perform an insert, update or delete.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, PersistRequest.Type type) {
|
||||
BeanManager<T> mgr = getBeanManager(bean);
|
||||
if (mgr == null) {
|
||||
throw new PersistenceException(errNotRegistered(bean.getClass()));
|
||||
}
|
||||
return (PersistRequestBean<T>) createRequest(bean, t, parentBean, mgr, type);
|
||||
return createRequest(bean, t, parentBean, mgr, type, false);
|
||||
}
|
||||
|
||||
private String errNotRegistered(Class<?> beanClass) {
|
||||
String msg = "The type [" + beanClass + "] is not a registered entity?";
|
||||
msg += " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
|
||||
msg += " If the entity is in a Jar check the ebean.search.jars property in ebean.properties file or check ServerConfig.addJar().";
|
||||
return msg;
|
||||
}
|
||||
/**
|
||||
* Create an Insert or Update PersistRequestBean when cascading.
|
||||
* <p>
|
||||
* This call determines the PersistRequest.Type based on bean state and the insert flag (root persist type).
|
||||
*/
|
||||
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, boolean insertMode) {
|
||||
BeanManager<T> mgr = getBeanManager(bean);
|
||||
if (mgr == null) {
|
||||
throw new PersistenceException(errNotRegistered(bean.getClass()));
|
||||
}
|
||||
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
|
||||
EntityBean entityBean = (EntityBean)bean;
|
||||
// determine Insert or Update based on bean state and insert flag
|
||||
PersistRequest.Type type = desc.isInsertMode(entityBean._ebean_getIntercept(), insertMode) ? Type.INSERT : Type.UPDATE;
|
||||
return createRequest(bean, t, parentBean, mgr, type, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Persist Request Object that wraps all the objects used to
|
||||
* perform an insert, update or delete.
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private PersistRequestBean<?> createRequest(Object bean, Transaction t, Object parentBean, BeanManager<?> mgr, PersistRequest.Type type) {
|
||||
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, BeanManager<?> mgr, PersistRequest.Type type, boolean saveRecurse) {
|
||||
|
||||
return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type);
|
||||
return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, saveRecurse);
|
||||
}
|
||||
|
||||
private String errNotRegistered(Class<?> beanClass) {
|
||||
String msg = "The type [" + beanClass + "] is not a registered entity?";
|
||||
msg += " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
|
||||
msg += " If the entity is in a Jar check the ebean.search.jars property in ebean.properties file or check ServerConfig.addJar().";
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for a bean that is being persisted.
|
||||
* <p>
|
||||
|
||||
@@ -144,7 +144,7 @@ public class CQueryBuilder implements Constants {
|
||||
String sqlSelect = "select count(*)";
|
||||
if (hasMany) {
|
||||
// need to count distinct id's ...
|
||||
query.setDistinct(true);
|
||||
query.setSqlDistinct(true);
|
||||
sqlSelect = null;
|
||||
}
|
||||
|
||||
@@ -320,13 +320,13 @@ public class CQueryBuilder implements Constants {
|
||||
|
||||
if (!useSqlLimiter) {
|
||||
sb.append("select ");
|
||||
if (query.isDistinct()) {
|
||||
if (query.isDistinctQuery()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(select.getSelectSql());
|
||||
if (query.isDistinct() && dbOrderBy != null) {
|
||||
if (query.isDistinctQuery() && dbOrderBy != null) {
|
||||
// add the orderby columns to the select clause (due to distinct)
|
||||
sb.append(", ").append(convertDbOrderByForSelect(dbOrderBy));
|
||||
}
|
||||
|
||||
@@ -258,7 +258,8 @@ public class SqlTreeBuilder {
|
||||
|
||||
// Optional many property for lazy loading query
|
||||
BeanPropertyAssocMany<?> lazyLoadMany = (query == null) ? null : query.getLazyLoadForParentsProperty();
|
||||
return new SqlTreeNodeRoot(desc, props, myList, !subQuery, includeJoin, lazyLoadMany);
|
||||
boolean withId = !subQuery && (query == null || !query.isDistinct());
|
||||
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany);
|
||||
|
||||
} else if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
return new SqlTreeNodeManyRoot(prefix, (BeanPropertyAssocMany<?>) prop, props, myList);
|
||||
@@ -312,7 +313,7 @@ public class SqlTreeBuilder {
|
||||
// as we are now going to join to the many then we need
|
||||
// to add the distinct to the sql query to stop duplicate
|
||||
// rows...
|
||||
query.setDistinct(true);
|
||||
query.setSqlDistinct(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
|
||||
Mode queryMode = ctx.getQueryMode();
|
||||
|
||||
PersistenceContext persistenceContext = ctx.getPersistenceContext();
|
||||
PersistenceContext persistenceContext = !readId ? null : ctx.getPersistenceContext();
|
||||
|
||||
Object id = null;
|
||||
if (!readId) {
|
||||
@@ -274,8 +274,9 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
} else if (localBean != null) {
|
||||
|
||||
ctx.setCurrentPrefix(prefix, pathMap);
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
|
||||
if (readId) {
|
||||
createListProxies(localDesc, ctx, localBean);
|
||||
}
|
||||
localDesc.postLoad(localBean, null);
|
||||
|
||||
if (localBean instanceof EntityBean) {
|
||||
@@ -290,7 +291,10 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
}
|
||||
|
||||
if (partialObject) {
|
||||
ctx.register(null, ebi);
|
||||
if (readId) {
|
||||
// register for lazy loading
|
||||
ctx.register(null, ebi);
|
||||
}
|
||||
} else {
|
||||
ebi.setFullyLoadedBean(true);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,8 +71,7 @@ public final class DefaultOrmUpdate<T> implements SpiUpdate<T>, Serializable {
|
||||
this.name = namedUpdate.getName();
|
||||
this.notifyCache = namedUpdate.isNotifyCache();
|
||||
|
||||
// named updates are always converted to sql as part
|
||||
// of the initialisation
|
||||
// named updates are always converted to sql as part of the initialisation
|
||||
this.updateStatement = namedUpdate.getSqlUpdateStatement();
|
||||
this.type = deriveType(updateStatement);
|
||||
}
|
||||
|
||||
@@ -223,7 +223,5 @@ public class DefaultRelationalQuery implements SpiSqlQuery {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@ package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
public class NaturalKeyBindParam {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Object value;
|
||||
|
||||
public NaturalKeyBindParam(String name, Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
private final String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
private final Object value;
|
||||
|
||||
public NaturalKeyBindParam(String name, Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,461 +27,456 @@ import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
* Holds the select() and join() details of a ORM query.
|
||||
* </p>
|
||||
* <p>
|
||||
* It is worth noting that for autoFetch a "tuned fetch info" builds an instance
|
||||
* of OrmQueryDetail. Tuning a query is a matter of replacing an instance of
|
||||
* this class with one that has been tuned with select() and join() set.
|
||||
* It is worth noting that for autoFetch a "tuned fetch info" builds an instance of OrmQueryDetail.
|
||||
* Tuning a query is a matter of replacing an instance of this class with one that has been tuned
|
||||
* with select() and join() set.
|
||||
* </p>
|
||||
*/
|
||||
public class OrmQueryDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2510486880141461807L;
|
||||
private static final long serialVersionUID = -2510486880141461807L;
|
||||
|
||||
/**
|
||||
* Root level properties.
|
||||
*/
|
||||
private OrmQueryProperties baseProps = new OrmQueryProperties();
|
||||
/**
|
||||
* Root level properties.
|
||||
*/
|
||||
private OrmQueryProperties baseProps = new OrmQueryProperties();
|
||||
|
||||
/**
|
||||
* Contains the fetch/lazy/query joins and their properties.
|
||||
*/
|
||||
private LinkedHashMap<String, OrmQueryProperties> fetchPaths = new LinkedHashMap<String, OrmQueryProperties>(8);
|
||||
/**
|
||||
* Contains the fetch/lazy/query joins and their properties.
|
||||
*/
|
||||
private LinkedHashMap<String, OrmQueryProperties> fetchPaths = new LinkedHashMap<String, OrmQueryProperties>(8);
|
||||
|
||||
private LinkedHashSet<String> includes = new LinkedHashSet<String>(8);
|
||||
private LinkedHashSet<String> includes = new LinkedHashSet<String>(8);
|
||||
|
||||
/**
|
||||
* Return a deep copy of the OrmQueryDetail.
|
||||
*/
|
||||
public OrmQueryDetail copy() {
|
||||
OrmQueryDetail copy = new OrmQueryDetail();
|
||||
copy.baseProps = baseProps.copy();
|
||||
for (Map.Entry<String, OrmQueryProperties> entry : fetchPaths.entrySet()) {
|
||||
copy.fetchPaths.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
copy.includes = new LinkedHashSet<String>(includes);
|
||||
return copy;
|
||||
/**
|
||||
* Return a deep copy of the OrmQueryDetail.
|
||||
*/
|
||||
public OrmQueryDetail copy() {
|
||||
OrmQueryDetail copy = new OrmQueryDetail();
|
||||
copy.baseProps = baseProps.copy();
|
||||
for (Map.Entry<String, OrmQueryProperties> entry : fetchPaths.entrySet()) {
|
||||
copy.fetchPaths.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
copy.includes = new LinkedHashSet<String>(includes);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash for the query plan.
|
||||
*/
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
if (baseProps == null) {
|
||||
builder.add(false);
|
||||
} else {
|
||||
builder.add(true);
|
||||
baseProps.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash for the query plan.
|
||||
*/
|
||||
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder) {
|
||||
if (baseProps == null) {
|
||||
builder.add(false);
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
p.queryPlanHash(request, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if equal in terms of autofetch (select and joins).
|
||||
*/
|
||||
public boolean isAutoFetchEqual(OrmQueryDetail otherDetail) {
|
||||
return autofetchPlanHash() == otherDetail.autofetchPlanHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash for the query plan.
|
||||
*/
|
||||
private int autofetchPlanHash() {
|
||||
|
||||
int hc = (baseProps == null ? 1 : baseProps.autofetchPlanHash());
|
||||
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
hc = hc * 31 + p.autofetchPlanHash();
|
||||
}
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (baseProps != null) {
|
||||
sb.append("select ").append(baseProps);
|
||||
}
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties join : fetchPaths.values()) {
|
||||
sb.append(" fetch ").append(join);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
throw new RuntimeException("should not use");
|
||||
}
|
||||
|
||||
/**
|
||||
* set the properties to include on the base / root entity.
|
||||
*/
|
||||
public void select(String columns) {
|
||||
baseProps = new OrmQueryProperties(null, columns);
|
||||
}
|
||||
|
||||
public boolean containsProperty(String property) {
|
||||
if (baseProps == null) {
|
||||
return true;
|
||||
} else {
|
||||
return baseProps.isIncluded(property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base / root query properties.
|
||||
*/
|
||||
public void setBase(OrmQueryProperties baseProps) {
|
||||
this.baseProps = baseProps;
|
||||
}
|
||||
|
||||
public List<OrmQueryProperties> removeSecondaryQueries() {
|
||||
return removeSecondaryQueries(false);
|
||||
}
|
||||
|
||||
public List<OrmQueryProperties> removeSecondaryLazyQueries() {
|
||||
return removeSecondaryQueries(true);
|
||||
}
|
||||
|
||||
private List<OrmQueryProperties> removeSecondaryQueries(boolean lazyQuery) {
|
||||
|
||||
ArrayList<String> matchingPaths = new ArrayList<String>(2);
|
||||
|
||||
for (OrmQueryProperties chunk : fetchPaths.values()) {
|
||||
boolean match = lazyQuery ? chunk.isLazyFetch() : chunk.isQueryFetch();
|
||||
if (match) {
|
||||
matchingPaths.add(chunk.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingPaths.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// sort into depth order to remove
|
||||
Collections.sort(matchingPaths);
|
||||
|
||||
// the list of secondary queries
|
||||
ArrayList<OrmQueryProperties> props = new ArrayList<OrmQueryProperties>(2);
|
||||
|
||||
for (int i = 0; i < matchingPaths.size(); i++) {
|
||||
String path = matchingPaths.get(i);
|
||||
includes.remove(path);
|
||||
OrmQueryProperties secQuery = fetchPaths.remove(path);
|
||||
if (secQuery == null) {
|
||||
// the path has already been removed by another
|
||||
// secondary query
|
||||
|
||||
} else {
|
||||
builder.add(true);
|
||||
baseProps.queryPlanHash(request, builder);
|
||||
}
|
||||
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
p.queryPlanHash(request, builder);
|
||||
props.add(secQuery);
|
||||
|
||||
// remove any child properties for this path
|
||||
Iterator<OrmQueryProperties> pass2It = fetchPaths.values().iterator();
|
||||
while (pass2It.hasNext()) {
|
||||
OrmQueryProperties pass2Prop = pass2It.next();
|
||||
if (secQuery.isChild(pass2Prop)) {
|
||||
// remove join to secondary query from the main query
|
||||
// and add to this secondary query
|
||||
pass2It.remove();
|
||||
includes.remove(pass2Prop.getPath());
|
||||
secQuery.add(pass2Prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if equal in terms of autofetch (select and joins).
|
||||
*/
|
||||
public boolean isAutoFetchEqual(OrmQueryDetail otherDetail) {
|
||||
return autofetchPlanHash() == otherDetail.autofetchPlanHash();
|
||||
// Add the secondary queries as select properties
|
||||
// to the parent chunk to ensure the foreign keys
|
||||
// are included in the query
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
String path = props.get(i).getPath();
|
||||
// split into parent and property
|
||||
String[] split = SplitName.split(path);
|
||||
// add property to parent chunk
|
||||
OrmQueryProperties chunk = getChunk(split[0], true);
|
||||
chunk.addSecondaryQueryJoin(split[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash for the query plan.
|
||||
*/
|
||||
private int autofetchPlanHash() {
|
||||
return props;
|
||||
}
|
||||
|
||||
int hc = (baseProps == null ? 1 : baseProps.autofetchPlanHash());
|
||||
public boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
|
||||
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
hc = hc * 31 + p.autofetchPlanHash();
|
||||
}
|
||||
}
|
||||
boolean tuned = false;
|
||||
|
||||
return hc;
|
||||
}
|
||||
OrmQueryProperties tunedRoot = tunedDetail.getChunk(null, false);
|
||||
if (tunedRoot != null && tunedRoot.hasProperties()) {
|
||||
tuned = true;
|
||||
baseProps.setTunedProperties(tunedRoot);
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (baseProps != null) {
|
||||
sb.append("select ").append(baseProps);
|
||||
}
|
||||
if (fetchPaths != null) {
|
||||
for (OrmQueryProperties join : fetchPaths.values()) {
|
||||
sb.append(" fetch ").append(join);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
throw new RuntimeException("should not use");
|
||||
}
|
||||
|
||||
/**
|
||||
* set the properties to include on the base / root entity.
|
||||
*/
|
||||
public void select(String columns) {
|
||||
baseProps = new OrmQueryProperties(null, columns);
|
||||
}
|
||||
|
||||
public boolean containsProperty(String property) {
|
||||
if (baseProps == null) {
|
||||
return true;
|
||||
for (OrmQueryProperties tunedChunk : tunedDetail.fetchPaths.values()) {
|
||||
OrmQueryProperties chunk = getChunk(tunedChunk.getPath(), false);
|
||||
if (chunk != null) {
|
||||
// set the properties to select
|
||||
chunk.setTunedProperties(tunedChunk);
|
||||
} else {
|
||||
return baseProps.isIncluded(property);
|
||||
// add a missing join
|
||||
putFetchPath(tunedChunk.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
return tuned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a join() method of the query.
|
||||
*/
|
||||
public void putFetchPath(OrmQueryProperties chunk) {
|
||||
String path = chunk.getPath();
|
||||
fetchPaths.put(path, chunk);
|
||||
includes.add(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all joins and properties.
|
||||
* <p>
|
||||
* Typically for the row count query.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
includes.clear();
|
||||
fetchPaths.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fetch properties and configuration for a given path.
|
||||
*
|
||||
* @param path
|
||||
* the property to join
|
||||
* @param partialProps
|
||||
* the properties on the join property to include
|
||||
*/
|
||||
public OrmQueryProperties addFetch(String path, String partialProps, FetchConfig fetchConfig) {
|
||||
|
||||
OrmQueryProperties chunk = getChunk(path, true);
|
||||
chunk.setProperties(partialProps);
|
||||
chunk.setFetchConfig(fetchConfig);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void sortFetchPaths(BeanDescriptor<?> d) {
|
||||
|
||||
LinkedHashMap<String, OrmQueryProperties> sorted = new LinkedHashMap<String, OrmQueryProperties>(fetchPaths.size());
|
||||
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
sortFetchPaths(d, p, sorted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base / root query properties.
|
||||
*/
|
||||
public void setBase(OrmQueryProperties baseProps) {
|
||||
this.baseProps = baseProps;
|
||||
}
|
||||
fetchPaths = sorted;
|
||||
}
|
||||
|
||||
public List<OrmQueryProperties> removeSecondaryQueries() {
|
||||
return removeSecondaryQueries(false);
|
||||
}
|
||||
private void sortFetchPaths(BeanDescriptor<?> d, OrmQueryProperties p,
|
||||
LinkedHashMap<String, OrmQueryProperties> sorted) {
|
||||
|
||||
public List<OrmQueryProperties> removeSecondaryLazyQueries() {
|
||||
return removeSecondaryQueries(true);
|
||||
}
|
||||
|
||||
private List<OrmQueryProperties> removeSecondaryQueries(boolean lazyQuery) {
|
||||
|
||||
ArrayList<String> matchingPaths = new ArrayList<String>(2);
|
||||
|
||||
for (OrmQueryProperties chunk : fetchPaths.values()) {
|
||||
boolean match = lazyQuery ? chunk.isLazyFetch() : chunk.isQueryFetch();
|
||||
if (match) {
|
||||
matchingPaths.add(chunk.getPath());
|
||||
}
|
||||
String path = p.getPath();
|
||||
if (!sorted.containsKey(path)) {
|
||||
String parentPath = p.getParentPath();
|
||||
if (parentPath == null || sorted.containsKey(parentPath)) {
|
||||
// off root path or parent already ahead in fetch order
|
||||
sorted.put(path, p);
|
||||
} else {
|
||||
OrmQueryProperties parentProp = fetchPaths.get(parentPath);
|
||||
if (parentProp == null) {
|
||||
ElPropertyValue el = d.getElGetValue(parentPath);
|
||||
if (el == null) {
|
||||
String msg = "Path [" + parentPath + "] not valid from " + d.getFullName();
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
// add a missing parent path just fetching the Id property
|
||||
BeanPropertyAssoc<?> assocOne = (BeanPropertyAssoc<?>) el.getBeanProperty();
|
||||
parentProp = new OrmQueryProperties(parentPath, assocOne.getTargetIdProperty());
|
||||
}
|
||||
|
||||
if (matchingPaths.size() == 0) {
|
||||
return null;
|
||||
if (parentProp != null) {
|
||||
sortFetchPaths(d, parentProp, sorted);
|
||||
}
|
||||
sorted.put(path, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort into depth order to remove
|
||||
Collections.sort(matchingPaths);
|
||||
/**
|
||||
* Convert 'fetch joins' to 'many' properties over to 'query joins'.
|
||||
*/
|
||||
public void convertManyFetchJoinsToQueryJoins(BeanDescriptor<?> beanDescriptor, String lazyLoadManyPath,
|
||||
boolean allowOne, int queryBatch) {
|
||||
|
||||
// the list of secondary queries
|
||||
ArrayList<OrmQueryProperties> props = new ArrayList<OrmQueryProperties>(2);
|
||||
ArrayList<OrmQueryProperties> manyChunks = new ArrayList<OrmQueryProperties>(3);
|
||||
|
||||
for (int i = 0; i < matchingPaths.size(); i++) {
|
||||
String path = matchingPaths.get(i);
|
||||
includes.remove(path);
|
||||
OrmQueryProperties secQuery = fetchPaths.remove(path);
|
||||
if (secQuery == null) {
|
||||
// the path has already been removed by another
|
||||
// secondary query
|
||||
// the name of the many fetch property if there is one
|
||||
String manyFetchProperty = null;
|
||||
|
||||
} else {
|
||||
props.add(secQuery);
|
||||
// flag that is set once the many fetch property is chosen
|
||||
boolean fetchJoinFirstMany = allowOne;
|
||||
|
||||
// remove any child properties for this path
|
||||
Iterator<OrmQueryProperties> pass2It = fetchPaths.values().iterator();
|
||||
while (pass2It.hasNext()) {
|
||||
OrmQueryProperties pass2Prop = pass2It.next();
|
||||
if (secQuery.isChild(pass2Prop)) {
|
||||
// remove join to secondary query from the main query
|
||||
// and add to this secondary query
|
||||
pass2It.remove();
|
||||
includes.remove(pass2Prop.getPath());
|
||||
secQuery.add(pass2Prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
sortFetchPaths(beanDescriptor);
|
||||
|
||||
for (String fetchPath : fetchPaths.keySet()) {
|
||||
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(fetchPath);
|
||||
if (elProp.containsManySince(manyFetchProperty)) {
|
||||
|
||||
// this is a join to a *ToMany
|
||||
OrmQueryProperties chunk = fetchPaths.get(fetchPath);
|
||||
if (chunk.isFetchJoin() && !isLazyLoadManyRoot(lazyLoadManyPath, chunk)
|
||||
&& !hasParentSecJoin(lazyLoadManyPath, chunk)) {
|
||||
// this is a 'fetch join' (included in main query)
|
||||
if (fetchJoinFirstMany) {
|
||||
// letting the first one remain a 'fetch join'
|
||||
fetchJoinFirstMany = false;
|
||||
manyFetchProperty = fetchPath;
|
||||
} else {
|
||||
// convert this one over to a 'query join'
|
||||
manyChunks.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the secondary queries as select properties
|
||||
// to the parent chunk to ensure the foreign keys
|
||||
// are included in the query
|
||||
for (int i = 0; i < props.size(); i++) {
|
||||
String path = props.get(i).getPath();
|
||||
// split into parent and property
|
||||
String[] split = SplitName.split(path);
|
||||
// add property to parent chunk
|
||||
OrmQueryProperties chunk = getChunk(split[0], true);
|
||||
chunk.addSecondaryQueryJoin(split[1]);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
|
||||
|
||||
boolean tuned = false;
|
||||
|
||||
OrmQueryProperties tunedRoot = tunedDetail.getChunk(null, false);
|
||||
if (tunedRoot != null && tunedRoot.hasProperties()) {
|
||||
tuned = true;
|
||||
baseProps.setTunedProperties(tunedRoot);
|
||||
|
||||
for (OrmQueryProperties tunedChunk : tunedDetail.fetchPaths.values()) {
|
||||
OrmQueryProperties chunk = getChunk(tunedChunk.getPath(), false);
|
||||
if (chunk != null) {
|
||||
// set the properties to select
|
||||
chunk.setTunedProperties(tunedChunk);
|
||||
} else {
|
||||
// add a missing join
|
||||
putFetchPath(tunedChunk.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
return tuned;
|
||||
for (int i = 0; i < manyChunks.size(); i++) {
|
||||
// convert 'fetch joins' over to 'query joins'
|
||||
manyChunks.get(i).setQueryFetch(queryBatch, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a join() method of the query.
|
||||
*/
|
||||
public void putFetchPath(OrmQueryProperties chunk) {
|
||||
String path = chunk.getPath();
|
||||
fetchPaths.put(path, chunk);
|
||||
includes.add(path);
|
||||
/**
|
||||
* Return true if this is actually the root level of a +query/+lazy loading query.
|
||||
*/
|
||||
private boolean isLazyLoadManyRoot(String lazyLoadManyPath, OrmQueryProperties chunk) {
|
||||
if (lazyLoadManyPath != null && lazyLoadManyPath.equals(chunk.getPath())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all joins and properties.
|
||||
* <p>
|
||||
* Typically for the row count query.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
includes.clear();
|
||||
fetchPaths.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fetch properties and configuration for a given path.
|
||||
*
|
||||
* @param path
|
||||
* the property to join
|
||||
* @param partialProps
|
||||
* the properties on the join property to include
|
||||
*/
|
||||
public OrmQueryProperties addFetch(String path, String partialProps, FetchConfig fetchConfig) {
|
||||
|
||||
OrmQueryProperties chunk = getChunk(path, true);
|
||||
chunk.setProperties(partialProps);
|
||||
chunk.setFetchConfig(fetchConfig);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void sortFetchPaths(BeanDescriptor<?> d) {
|
||||
|
||||
LinkedHashMap<String, OrmQueryProperties> sorted = new LinkedHashMap<String, OrmQueryProperties>(fetchPaths.size());
|
||||
|
||||
for (OrmQueryProperties p : fetchPaths.values()) {
|
||||
sortFetchPaths(d, p, sorted);
|
||||
}
|
||||
|
||||
fetchPaths = sorted;
|
||||
}
|
||||
|
||||
private void sortFetchPaths(BeanDescriptor<?> d, OrmQueryProperties p,
|
||||
LinkedHashMap<String, OrmQueryProperties> sorted) {
|
||||
|
||||
String path = p.getPath();
|
||||
if (!sorted.containsKey(path)) {
|
||||
String parentPath = p.getParentPath();
|
||||
if (parentPath == null || sorted.containsKey(parentPath)) {
|
||||
// off root path or parent already ahead in fetch order
|
||||
sorted.put(path, p);
|
||||
} else {
|
||||
OrmQueryProperties parentProp = fetchPaths.get(parentPath);
|
||||
if (parentProp == null) {
|
||||
ElPropertyValue el = d.getElGetValue(parentPath);
|
||||
if (el == null) {
|
||||
String msg = "Path [" + parentPath + "] not valid from " + d.getFullName();
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
// add a missing parent path just fetching the Id property
|
||||
BeanPropertyAssoc<?> assocOne = (BeanPropertyAssoc<?>) el.getBeanProperty();
|
||||
parentProp = new OrmQueryProperties(parentPath, assocOne.getTargetIdProperty());
|
||||
}
|
||||
if (parentProp != null) {
|
||||
sortFetchPaths(d, parentProp, sorted);
|
||||
}
|
||||
sorted.put(path, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 'fetch joins' to 'many' properties over to 'query joins'.
|
||||
*/
|
||||
public void convertManyFetchJoinsToQueryJoins(BeanDescriptor<?> beanDescriptor, String lazyLoadManyPath,
|
||||
boolean allowOne, int queryBatch) {
|
||||
|
||||
ArrayList<OrmQueryProperties> manyChunks = new ArrayList<OrmQueryProperties>(3);
|
||||
|
||||
// the name of the many fetch property if there is one
|
||||
String manyFetchProperty = null;
|
||||
|
||||
// flag that is set once the many fetch property is chosen
|
||||
boolean fetchJoinFirstMany = allowOne;
|
||||
|
||||
sortFetchPaths(beanDescriptor);
|
||||
|
||||
for (String fetchPath : fetchPaths.keySet()) {
|
||||
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(fetchPath);
|
||||
if (elProp.containsManySince(manyFetchProperty)) {
|
||||
|
||||
// this is a join to a *ToMany
|
||||
OrmQueryProperties chunk = fetchPaths.get(fetchPath);
|
||||
if (chunk.isFetchJoin()
|
||||
&& !isLazyLoadManyRoot(lazyLoadManyPath, chunk)
|
||||
&& !hasParentSecJoin(lazyLoadManyPath, chunk)) {
|
||||
// this is a 'fetch join' (included in main query)
|
||||
if (fetchJoinFirstMany) {
|
||||
// letting the first one remain a 'fetch join'
|
||||
fetchJoinFirstMany = false;
|
||||
manyFetchProperty = fetchPath;
|
||||
} else {
|
||||
// convert this one over to a 'query join'
|
||||
manyChunks.add(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < manyChunks.size(); i++) {
|
||||
// convert 'fetch joins' over to 'query joins'
|
||||
manyChunks.get(i).setQueryFetch(queryBatch, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is actually the root level of a +query/+lazy loading
|
||||
* query.
|
||||
*/
|
||||
private boolean isLazyLoadManyRoot(String lazyLoadManyPath, OrmQueryProperties chunk) {
|
||||
if (lazyLoadManyPath != null && lazyLoadManyPath.equals(chunk.getPath())) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* If the chunk has a parent that is a query or lazy join. In this case it does not need to be
|
||||
* converted.
|
||||
*/
|
||||
private boolean hasParentSecJoin(String lazyLoadManyPath, OrmQueryProperties chunk) {
|
||||
OrmQueryProperties parent = getParent(chunk);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (lazyLoadManyPath != null && lazyLoadManyPath.equals(parent.getPath())) {
|
||||
return false;
|
||||
} else if (!parent.isFetchJoin()) {
|
||||
return true;
|
||||
} else {
|
||||
return hasParentSecJoin(lazyLoadManyPath, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent chunk.
|
||||
*/
|
||||
private OrmQueryProperties getParent(OrmQueryProperties chunk) {
|
||||
String parentPath = chunk.getParentPath();
|
||||
return parentPath == null ? null : fetchPaths.get(parentPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set any default select clauses for the main bean and any joins that have not explicitly defined
|
||||
* a select clause.
|
||||
* <p>
|
||||
* That is this will use FetchType.LAZY to exclude some properties by default.
|
||||
* </p>
|
||||
*/
|
||||
public void setDefaultSelectClause(BeanDescriptor<?> desc) {
|
||||
|
||||
if (desc.hasDefaultSelectClause() && !hasSelectClause()) {
|
||||
if (baseProps == null) {
|
||||
baseProps = new OrmQueryProperties();
|
||||
}
|
||||
baseProps.setDefaultProperties(desc.getDefaultSelectClause(), desc.getDefaultSelectClauseSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the chunk has a parent that is a query or lazy join. In this case it
|
||||
* does not need to be converted.
|
||||
*/
|
||||
private boolean hasParentSecJoin(String lazyLoadManyPath, OrmQueryProperties chunk) {
|
||||
OrmQueryProperties parent = getParent(chunk);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (lazyLoadManyPath != null && lazyLoadManyPath.equals(parent.getPath())) {
|
||||
return false;
|
||||
} else if (!parent.isFetchJoin()) {
|
||||
return true;
|
||||
} else {
|
||||
return hasParentSecJoin(lazyLoadManyPath, parent);
|
||||
}
|
||||
for (OrmQueryProperties joinProps : fetchPaths.values()) {
|
||||
if (!joinProps.hasSelectClause()) {
|
||||
BeanDescriptor<?> assocDesc = desc.getBeanDescriptor(joinProps.getPath());
|
||||
if (assocDesc.hasDefaultSelectClause()) {
|
||||
// use the default select clause
|
||||
joinProps.setDefaultProperties(assocDesc.getDefaultSelectClause(), assocDesc.getDefaultSelectClauseSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent chunk.
|
||||
*/
|
||||
private OrmQueryProperties getParent(OrmQueryProperties chunk) {
|
||||
String parentPath = chunk.getParentPath();
|
||||
return parentPath == null ? null : fetchPaths.get(parentPath);
|
||||
public boolean hasSelectClause() {
|
||||
return (baseProps != null && baseProps.hasSelectClause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query detail has neither select properties specified or any joins defined.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return fetchPaths.isEmpty() && (baseProps == null || !baseProps.hasProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no joins.
|
||||
*/
|
||||
public boolean isJoinsEmpty() {
|
||||
return fetchPaths.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the explicit bean join.
|
||||
* <p>
|
||||
* This is also used to Exclude the matching property from the parent select (aka remove the
|
||||
* foreign key) because it is now included in it's on node in the SqlTree.
|
||||
* </p>
|
||||
*/
|
||||
public void includeBeanJoin(String parentPath, String propertyName) {
|
||||
OrmQueryProperties parentChunk = getChunk(parentPath, true);
|
||||
parentChunk.includeBeanJoin(propertyName);
|
||||
}
|
||||
|
||||
public OrmQueryProperties getChunk(String path, boolean create) {
|
||||
if (path == null) {
|
||||
return baseProps;
|
||||
}
|
||||
OrmQueryProperties props = fetchPaths.get(path);
|
||||
if (create && props == null) {
|
||||
props = new OrmQueryProperties(path);
|
||||
putFetchPath(props);
|
||||
return props;
|
||||
|
||||
/**
|
||||
* Set any default select clauses for the main bean and any joins that have
|
||||
* not explicitly defined a select clause.
|
||||
* <p>
|
||||
* That is this will use FetchType.LAZY to exclude some properties by
|
||||
* default.
|
||||
* </p>
|
||||
*/
|
||||
public void setDefaultSelectClause(BeanDescriptor<?> desc) {
|
||||
|
||||
if (desc.hasDefaultSelectClause() && !hasSelectClause()) {
|
||||
if (baseProps == null) {
|
||||
baseProps = new OrmQueryProperties();
|
||||
}
|
||||
baseProps.setDefaultProperties(desc.getDefaultSelectClause(), desc.getDefaultSelectClauseSet());
|
||||
}
|
||||
|
||||
for (OrmQueryProperties joinProps : fetchPaths.values()) {
|
||||
if (!joinProps.hasSelectClause()) {
|
||||
BeanDescriptor<?> assocDesc = desc.getBeanDescriptor(joinProps.getPath());
|
||||
if (assocDesc.hasDefaultSelectClause()) {
|
||||
// use the default select clause
|
||||
joinProps.setDefaultProperties(assocDesc.getDefaultSelectClause(), assocDesc.getDefaultSelectClauseSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSelectClause() {
|
||||
return (baseProps != null && baseProps.hasSelectClause());
|
||||
}
|
||||
/**
|
||||
* Return true if the property is included.
|
||||
*/
|
||||
public boolean includes(String path) {
|
||||
|
||||
/**
|
||||
* Return true if the query detail has neither select properties specified
|
||||
* or any joins defined.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return fetchPaths.isEmpty() && (baseProps == null || !baseProps.hasProperties());
|
||||
}
|
||||
OrmQueryProperties chunk = fetchPaths.get(path);
|
||||
|
||||
/**
|
||||
* Return true if there are no joins.
|
||||
*/
|
||||
public boolean isJoinsEmpty() {
|
||||
return fetchPaths.isEmpty();
|
||||
}
|
||||
// may not have fetch properties if just +cache etc
|
||||
return chunk != null && !chunk.isCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the explicit bean join.
|
||||
* <p>
|
||||
* This is also used to Exclude the matching property from the parent select
|
||||
* (aka remove the foreign key) because it is now included in it's on node
|
||||
* in the SqlTree.
|
||||
* </p>
|
||||
*/
|
||||
public void includeBeanJoin(String parentPath, String propertyName) {
|
||||
OrmQueryProperties parentChunk = getChunk(parentPath, true);
|
||||
parentChunk.includeBeanJoin(propertyName);
|
||||
}
|
||||
|
||||
public OrmQueryProperties getChunk(String path, boolean create) {
|
||||
if (path == null) {
|
||||
return baseProps;
|
||||
}
|
||||
OrmQueryProperties props = fetchPaths.get(path);
|
||||
if (create && props == null) {
|
||||
props = new OrmQueryProperties(path);
|
||||
putFetchPath(props);
|
||||
return props;
|
||||
|
||||
} else {
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is included.
|
||||
*/
|
||||
public boolean includes(String path) {
|
||||
|
||||
OrmQueryProperties chunk = fetchPaths.get(path);
|
||||
|
||||
// may not have fetch properties if just +cache etc
|
||||
return chunk != null && !chunk.isCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property includes for this detail.
|
||||
*/
|
||||
public HashSet<String> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
/**
|
||||
* Return the property includes for this detail.
|
||||
*/
|
||||
public HashSet<String> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
}
|
||||
|
||||
+159
-161
@@ -3,198 +3,196 @@ package com.avaje.ebeaninternal.server.querydefn;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* Parses a Object relational query statement into a OrmQueryDetail and
|
||||
* OrmQueryAttributes.
|
||||
* Parses a Object relational query statement into a OrmQueryDetail and OrmQueryAttributes.
|
||||
* <p>
|
||||
* The reason they are split into detail and attributes is that the autoFetch
|
||||
* feature is used to replace the OrmQueryDetail leaving the attributes
|
||||
* unchanged.
|
||||
* The reason they are split into detail and attributes is that the autoFetch feature is used to
|
||||
* replace the OrmQueryDetail leaving the attributes unchanged.
|
||||
* </p>
|
||||
*/
|
||||
public class OrmQueryDetailParser {
|
||||
|
||||
private final OrmQueryDetail detail = new OrmQueryDetail();
|
||||
private final OrmQueryDetail detail = new OrmQueryDetail();
|
||||
|
||||
private int maxRows;
|
||||
private int maxRows;
|
||||
|
||||
private int firstRow;
|
||||
private int firstRow;
|
||||
|
||||
private String rawWhereClause;
|
||||
private String rawWhereClause;
|
||||
|
||||
private String rawOrderBy;
|
||||
private String rawOrderBy;
|
||||
|
||||
private final SimpleTextParser parser;
|
||||
private final SimpleTextParser parser;
|
||||
|
||||
public OrmQueryDetailParser(String oql) {
|
||||
this.parser = new SimpleTextParser(oql);
|
||||
public OrmQueryDetailParser(String oql) {
|
||||
this.parser = new SimpleTextParser(oql);
|
||||
}
|
||||
|
||||
public void parse() throws PersistenceException {
|
||||
|
||||
parser.nextWord();
|
||||
processInitial();
|
||||
}
|
||||
|
||||
protected void assign(DefaultOrmQuery<?> query) {
|
||||
query.setOrmQueryDetail(detail);
|
||||
query.setFirstRow(firstRow);
|
||||
query.setMaxRows(maxRows);
|
||||
query.setRawWhereClause(rawWhereClause);
|
||||
query.order(rawOrderBy);
|
||||
}
|
||||
|
||||
private void processInitial() {
|
||||
if (parser.isMatch("find")) {
|
||||
OrmQueryProperties props = readFindFetch();
|
||||
detail.setBase(props);
|
||||
} else {
|
||||
process();
|
||||
}
|
||||
while (!parser.isFinished()) {
|
||||
process();
|
||||
}
|
||||
}
|
||||
|
||||
public void parse() throws PersistenceException {
|
||||
private boolean isFetch() {
|
||||
return parser.isMatch("fetch") || parser.isMatch("join");
|
||||
}
|
||||
|
||||
private void process() {
|
||||
if (isFetch()) {
|
||||
OrmQueryProperties props = readFindFetch();
|
||||
detail.putFetchPath(props);
|
||||
|
||||
} else if (parser.isMatch("where")) {
|
||||
readWhere();
|
||||
|
||||
} else if (parser.isMatch("order", "by")) {
|
||||
readOrderBy();
|
||||
|
||||
} else if (parser.isMatch("limit")) {
|
||||
readLimit();
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Query expected 'fetch', 'where','order by' or 'limit' keyword but got ["
|
||||
+ parser.getWord() + "] \r " + parser.getOql());
|
||||
}
|
||||
}
|
||||
|
||||
private void readLimit() {
|
||||
try {
|
||||
String maxLimit = parser.nextWord();
|
||||
maxRows = Integer.parseInt(maxLimit);
|
||||
|
||||
String offsetKeyword = parser.nextWord();
|
||||
if (offsetKeyword != null) {
|
||||
if (!parser.isMatch("offset")) {
|
||||
throw new PersistenceException("expected offset keyword but got " + parser.getWord());
|
||||
}
|
||||
String firstRowLimit = parser.nextWord();
|
||||
firstRow = Integer.parseInt(firstRowLimit);
|
||||
parser.nextWord();
|
||||
processInitial();
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Expected an integer for maxRows or firstRows in limit offset clause";
|
||||
throw new PersistenceException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void assign(DefaultOrmQuery<?> query) {
|
||||
query.setOrmQueryDetail(detail);
|
||||
query.setFirstRow(firstRow);
|
||||
query.setMaxRows(maxRows);
|
||||
query.setRawWhereClause(rawWhereClause);
|
||||
query.order(rawOrderBy);
|
||||
}
|
||||
private void readOrderBy() {
|
||||
// read the by
|
||||
parser.nextWord();
|
||||
|
||||
private void processInitial() {
|
||||
if (parser.isMatch("find")) {
|
||||
OrmQueryProperties props = readFindFetch();
|
||||
detail.setBase(props);
|
||||
} else {
|
||||
process();
|
||||
}
|
||||
while (!parser.isFinished()) {
|
||||
process();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (parser.nextWord() != null) {
|
||||
if (parser.isMatch("limit")) {
|
||||
break;
|
||||
} else {
|
||||
String w = parser.getWord();
|
||||
if (!w.startsWith("(")) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(w);
|
||||
}
|
||||
}
|
||||
rawOrderBy = sb.toString().trim();
|
||||
|
||||
if (!parser.isFinished()) {
|
||||
readLimit();
|
||||
}
|
||||
}
|
||||
|
||||
private void readWhere() {
|
||||
|
||||
int nextMode = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((parser.nextWord()) != null) {
|
||||
if (parser.isMatch("order", "by")) {
|
||||
nextMode = 1;
|
||||
break;
|
||||
|
||||
} else if (parser.isMatch("limit")) {
|
||||
nextMode = 2;
|
||||
break;
|
||||
|
||||
} else {
|
||||
sb.append(" ").append(parser.getWord());
|
||||
}
|
||||
}
|
||||
String whereClause = sb.toString().trim();
|
||||
if (whereClause.length() > 0) {
|
||||
rawWhereClause = whereClause;
|
||||
}
|
||||
|
||||
private boolean isFetch() {
|
||||
return parser.isMatch("fetch") || parser.isMatch("join");
|
||||
if (nextMode == 1) {
|
||||
readOrderBy();
|
||||
} else if (nextMode == 2) {
|
||||
readLimit();
|
||||
}
|
||||
}
|
||||
|
||||
private void process() {
|
||||
if (isFetch()) {
|
||||
OrmQueryProperties props = readFindFetch();
|
||||
detail.putFetchPath(props);
|
||||
private OrmQueryProperties readFindFetch() {
|
||||
|
||||
} else if (parser.isMatch("where")) {
|
||||
readWhere();
|
||||
boolean readAlias = false;
|
||||
|
||||
} else if (parser.isMatch("order", "by")) {
|
||||
readOrderBy();
|
||||
|
||||
} else if (parser.isMatch("limit")) {
|
||||
readLimit();
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Query expected 'fetch', 'where','order by' or 'limit' keyword but got ["
|
||||
+ parser.getWord() + "] \r " + parser.getOql());
|
||||
}
|
||||
}
|
||||
|
||||
private void readLimit() {
|
||||
try {
|
||||
String maxLimit = parser.nextWord();
|
||||
maxRows = Integer.parseInt(maxLimit);
|
||||
|
||||
String offsetKeyword = parser.nextWord();
|
||||
if (offsetKeyword != null) {
|
||||
if (!parser.isMatch("offset")) {
|
||||
throw new PersistenceException("expected offset keyword but got " + parser.getWord());
|
||||
}
|
||||
String firstRowLimit = parser.nextWord();
|
||||
firstRow = Integer.parseInt(firstRowLimit);
|
||||
parser.nextWord();
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = "Expected an integer for maxRows or firstRows in limit offset clause";
|
||||
throw new PersistenceException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void readOrderBy() {
|
||||
// read the by
|
||||
String props = null;
|
||||
String path = parser.nextWord();
|
||||
String token = null;
|
||||
while ((token = parser.nextWord()) != null) {
|
||||
if (!readAlias && parser.isMatch("as")) {
|
||||
// next token is alias
|
||||
parser.nextWord();
|
||||
readAlias = true;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (parser.nextWord() != null) {
|
||||
if (parser.isMatch("limit")) {
|
||||
break;
|
||||
} else {
|
||||
String w = parser.getWord();
|
||||
if (!w.startsWith("(")) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(w);
|
||||
}
|
||||
}
|
||||
rawOrderBy = sb.toString().trim();
|
||||
} else if ('(' == token.charAt(0)) {
|
||||
props = token;
|
||||
parser.nextWord();
|
||||
break;
|
||||
|
||||
if (!parser.isFinished()) {
|
||||
readLimit();
|
||||
}
|
||||
} else if (isFindFetchEnd()) {
|
||||
break;
|
||||
|
||||
} else if (!readAlias) {
|
||||
readAlias = true;
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Expected (props) or new 'fetch' 'where' but got " + token);
|
||||
}
|
||||
}
|
||||
|
||||
private void readWhere() {
|
||||
|
||||
int nextMode = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((parser.nextWord()) != null) {
|
||||
if (parser.isMatch("order", "by")) {
|
||||
nextMode = 1;
|
||||
break;
|
||||
|
||||
} else if (parser.isMatch("limit")) {
|
||||
nextMode = 2;
|
||||
break;
|
||||
|
||||
} else {
|
||||
sb.append(" ").append(parser.getWord());
|
||||
}
|
||||
}
|
||||
String whereClause = sb.toString().trim();
|
||||
if (whereClause.length() > 0) {
|
||||
rawWhereClause = whereClause;
|
||||
}
|
||||
|
||||
if (nextMode == 1) {
|
||||
readOrderBy();
|
||||
} else if (nextMode == 2) {
|
||||
readLimit();
|
||||
}
|
||||
if (props != null) {
|
||||
props = props.substring(1, props.length() - 1);
|
||||
}
|
||||
return new OrmQueryProperties(path, props);
|
||||
}
|
||||
|
||||
private OrmQueryProperties readFindFetch() {
|
||||
|
||||
boolean readAlias = false;
|
||||
|
||||
String props = null;
|
||||
String path = parser.nextWord();
|
||||
String token = null;
|
||||
while ((token = parser.nextWord()) != null) {
|
||||
if (!readAlias && parser.isMatch("as")) {
|
||||
// next token is alias
|
||||
parser.nextWord();
|
||||
readAlias = true;
|
||||
|
||||
} else if ('(' == token.charAt(0)) {
|
||||
props = token;
|
||||
parser.nextWord();
|
||||
break;
|
||||
|
||||
} else if (isFindFetchEnd()) {
|
||||
break;
|
||||
|
||||
} else if (!readAlias) {
|
||||
readAlias = true;
|
||||
|
||||
} else {
|
||||
throw new PersistenceException("Expected (props) or new 'fetch' 'where' but got " + token);
|
||||
}
|
||||
}
|
||||
if (props != null) {
|
||||
props = props.substring(1, props.length() - 1);
|
||||
}
|
||||
return new OrmQueryProperties(path, props);
|
||||
private boolean isFindFetchEnd() {
|
||||
if (isFetch()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isFindFetchEnd() {
|
||||
if (isFetch()) {
|
||||
return true;
|
||||
}
|
||||
if (parser.isMatch("where")) {
|
||||
return true;
|
||||
}
|
||||
if (parser.isMatch("order", "by")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (parser.isMatch("where")) {
|
||||
return true;
|
||||
}
|
||||
if (parser.isMatch("order", "by")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,40 +6,40 @@ import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
public class OrmQueryLimitRequest implements SqlLimitRequest {
|
||||
|
||||
private final SpiQuery<?> ormQuery;
|
||||
|
||||
private final SpiQuery<?> ormQuery;
|
||||
|
||||
private final DatabasePlatform dbPlatform;
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final String sqlOrderBy;
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final String sqlOrderBy;
|
||||
|
||||
public OrmQueryLimitRequest(String sql, String sqlOrderBy, SpiQuery<?> ormQuery, DatabasePlatform dbPlatform) {
|
||||
this.sql = sql;
|
||||
this.sqlOrderBy = sqlOrderBy;
|
||||
this.ormQuery = ormQuery;
|
||||
this.dbPlatform = dbPlatform;
|
||||
}
|
||||
|
||||
public String getDbOrderBy() {
|
||||
return sqlOrderBy;
|
||||
}
|
||||
|
||||
public String getDbSql() {
|
||||
return sql;
|
||||
}
|
||||
public String getDbOrderBy() {
|
||||
return sqlOrderBy;
|
||||
}
|
||||
|
||||
public int getFirstRow() {
|
||||
return ormQuery.getFirstRow();
|
||||
}
|
||||
public String getDbSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public int getMaxRows() {
|
||||
return ormQuery.getMaxRows();
|
||||
}
|
||||
public int getFirstRow() {
|
||||
return ormQuery.getFirstRow();
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return ormQuery.isDistinct();
|
||||
}
|
||||
public int getMaxRows() {
|
||||
return ormQuery.getMaxRows();
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return ormQuery.isDistinctQuery();
|
||||
}
|
||||
|
||||
public SpiQuery<?> getOrmQuery() {
|
||||
return ormQuery;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,176 +2,176 @@ package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
public class SimpleTextParser {
|
||||
|
||||
private final String oql;
|
||||
private final char[] chars;
|
||||
private final int eof;
|
||||
private final String oql;
|
||||
private final char[] chars;
|
||||
private final int eof;
|
||||
|
||||
private int pos;
|
||||
private String word;
|
||||
private String lowerWord;
|
||||
private int pos;
|
||||
private String word;
|
||||
private String lowerWord;
|
||||
|
||||
private int openParenthesisCount;
|
||||
private int openParenthesisCount;
|
||||
|
||||
public SimpleTextParser(String oql) {
|
||||
this.oql = oql;
|
||||
this.chars = oql.toCharArray();
|
||||
this.eof = oql.length();
|
||||
}
|
||||
public SimpleTextParser(String oql) {
|
||||
this.oql = oql;
|
||||
this.chars = oql.toCharArray();
|
||||
this.eof = oql.length();
|
||||
}
|
||||
|
||||
public int getPos() {
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public String getOql() {
|
||||
return oql;
|
||||
}
|
||||
return oql;
|
||||
}
|
||||
|
||||
public String getWord() {
|
||||
return word;
|
||||
}
|
||||
public String getWord() {
|
||||
return word;
|
||||
}
|
||||
|
||||
public String peekNextWord() {
|
||||
int origPos = pos;
|
||||
String nw = nextWordInternal();
|
||||
pos = origPos;
|
||||
return nw;
|
||||
}
|
||||
public String peekNextWord() {
|
||||
int origPos = pos;
|
||||
String nw = nextWordInternal();
|
||||
pos = origPos;
|
||||
return nw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current and the next word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch, String nextWordMatch) {
|
||||
/**
|
||||
* Match the current and the next word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch, String nextWordMatch) {
|
||||
|
||||
if (isMatch(lowerMatch)) {
|
||||
String nw = peekNextWord();
|
||||
if (nw != null) {
|
||||
nw = nw.toLowerCase();
|
||||
return nw.equals(nextWordMatch);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (isMatch(lowerMatch)) {
|
||||
String nw = peekNextWord();
|
||||
if (nw != null) {
|
||||
nw = nw.toLowerCase();
|
||||
return nw.equals(nextWordMatch);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return word == null;
|
||||
}
|
||||
public boolean isFinished() {
|
||||
return word == null;
|
||||
}
|
||||
|
||||
public int findWordLower(String lowerMatch, int afterPos) {
|
||||
this.pos = afterPos;
|
||||
return findWordLower(lowerMatch);
|
||||
}
|
||||
public int findWordLower(String lowerMatch, int afterPos) {
|
||||
this.pos = afterPos;
|
||||
return findWordLower(lowerMatch);
|
||||
}
|
||||
|
||||
public int findWordLower(String lowerMatch) {
|
||||
do {
|
||||
if (nextWord() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (lowerMatch.equals(lowerWord)) {
|
||||
return pos - lowerWord.length();
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
public int findWordLower(String lowerMatch) {
|
||||
do {
|
||||
if (nextWord() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (lowerMatch.equals(lowerWord)) {
|
||||
return pos - lowerWord.length();
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the current word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch) {
|
||||
return lowerMatch.equals(lowerWord);
|
||||
}
|
||||
/**
|
||||
* Match the current word.
|
||||
*/
|
||||
public boolean isMatch(String lowerMatch) {
|
||||
return lowerMatch.equals(lowerWord);
|
||||
}
|
||||
|
||||
public String nextWord() {
|
||||
word = nextWordInternal();
|
||||
if (word != null) {
|
||||
lowerWord = word.toLowerCase();
|
||||
}
|
||||
return word;
|
||||
}
|
||||
public String nextWord() {
|
||||
word = nextWordInternal();
|
||||
if (word != null) {
|
||||
lowerWord = word.toLowerCase();
|
||||
}
|
||||
return word;
|
||||
}
|
||||
|
||||
private String nextWordInternal() {
|
||||
trimLeadingWhitespace();
|
||||
if (pos >= eof) {
|
||||
return null;
|
||||
}
|
||||
int start = pos;
|
||||
if (chars[pos] == '(') {
|
||||
moveToClose();
|
||||
} else {
|
||||
moveToEndOfWord();
|
||||
}
|
||||
return oql.substring(start, pos);
|
||||
}
|
||||
private String nextWordInternal() {
|
||||
trimLeadingWhitespace();
|
||||
if (pos >= eof) {
|
||||
return null;
|
||||
}
|
||||
int start = pos;
|
||||
if (chars[pos] == '(') {
|
||||
moveToClose();
|
||||
} else {
|
||||
moveToEndOfWord();
|
||||
}
|
||||
return oql.substring(start, pos);
|
||||
}
|
||||
|
||||
private void moveToClose() {
|
||||
private void moveToClose() {
|
||||
|
||||
pos++;
|
||||
openParenthesisCount = 0;
|
||||
pos++;
|
||||
openParenthesisCount = 0;
|
||||
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (c == '(') {
|
||||
// count nested parenthesis
|
||||
openParenthesisCount++;
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (c == '(') {
|
||||
// count nested parenthesis
|
||||
openParenthesisCount++;
|
||||
|
||||
} else if (c == ')') {
|
||||
if (openParenthesisCount > 0) {
|
||||
// still in nested parenthesis
|
||||
--openParenthesisCount;
|
||||
} else {
|
||||
// we have found the end
|
||||
pos++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (c == ')') {
|
||||
if (openParenthesisCount > 0) {
|
||||
// still in nested parenthesis
|
||||
--openParenthesisCount;
|
||||
} else {
|
||||
// we have found the end
|
||||
pos++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToEndOfWord() {
|
||||
char c = chars[pos];
|
||||
boolean isOperator = isOperator(c);
|
||||
for (; pos < eof; pos++) {
|
||||
c = chars[pos];
|
||||
if (isWordTerminator(c, isOperator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void moveToEndOfWord() {
|
||||
char c = chars[pos];
|
||||
boolean isOperator = isOperator(c);
|
||||
for (; pos < eof; pos++) {
|
||||
c = chars[pos];
|
||||
if (isWordTerminator(c, isOperator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWordTerminator(char c, boolean isOperator) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
if (isOperator(c)) {
|
||||
return !isOperator;
|
||||
}
|
||||
if (c == '('){
|
||||
return true;
|
||||
}
|
||||
private boolean isWordTerminator(char c, boolean isOperator) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
if (isOperator(c)) {
|
||||
return !isOperator;
|
||||
}
|
||||
if (c == '(') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isOperator;
|
||||
}
|
||||
return isOperator;
|
||||
}
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
switch (c) {
|
||||
case '<':
|
||||
return true;
|
||||
case '>':
|
||||
return true;
|
||||
case '=':
|
||||
return true;
|
||||
case '!':
|
||||
return true;
|
||||
private boolean isOperator(char c) {
|
||||
switch (c) {
|
||||
case '<':
|
||||
return true;
|
||||
case '>':
|
||||
return true;
|
||||
case '=':
|
||||
return true;
|
||||
case '!':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void trimLeadingWhitespace() {
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (!Character.isWhitespace(c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void trimLeadingWhitespace() {
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
if (!Character.isWhitespace(c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class BeanReflectProperties {
|
||||
return (String[]) field.get(null);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
throw new IllegalStateException("Error getting _ebean_props field on type "+clazz, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* AutoCommit friendly Transaction.
|
||||
* <p>
|
||||
* Skips actual commit and rollback as these are performed automatically.
|
||||
*/
|
||||
public class AutoCommitJdbcTransaction extends JdbcTransaction {
|
||||
|
||||
public AutoCommitJdbcTransaction(String id, boolean explicit, Connection connection, TransactionManager manager) {
|
||||
super(id, explicit, connection, manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performRollback() throws SQLException {
|
||||
// do nothing as autoCommit
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommit() throws SQLException {
|
||||
// do nothing as autoCommit
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
|
||||
/**
|
||||
* AutoCommit based TransactionManager.
|
||||
* <p>
|
||||
* Intended to be used if when autoCommit mode is desired.
|
||||
*/
|
||||
public class AutoCommitTransactionManager extends TransactionManager {
|
||||
|
||||
public AutoCommitTransactionManager(ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
ServerConfig config, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
|
||||
|
||||
super(clusterManager, backgroundExecutor, config, descMgr, bootupClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an autoCommit based Transaction.
|
||||
*/
|
||||
@Override
|
||||
protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) {
|
||||
|
||||
return new AutoCommitJdbcTransaction(prefix + id, explicit, c, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -50,11 +50,6 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
*/
|
||||
protected final boolean explicit;
|
||||
|
||||
/**
|
||||
* Set to true if the connection has autoCommit=true initially.
|
||||
*/
|
||||
protected final boolean autoCommit;
|
||||
|
||||
/**
|
||||
* Behaviour for ending query only transactions.
|
||||
*/
|
||||
@@ -136,14 +131,10 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
try {
|
||||
this.active = true;
|
||||
this.id = id;
|
||||
this.logPrefix = deriveLogPrefix(id,null);
|
||||
this.logPrefix = deriveLogPrefix(id);
|
||||
this.explicit = explicit;
|
||||
this.manager = manager;
|
||||
this.connection = connection;
|
||||
this.autoCommit = connection.getAutoCommit();
|
||||
if (this.autoCommit) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
this.onQueryOnly = manager == null ? OnQueryOnly.ROLLBACK : manager.getOnQueryOnly();
|
||||
this.persistenceContext = new DefaultPersistenceContext();
|
||||
|
||||
@@ -152,23 +143,17 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
private static String deriveLogPrefix(String id, String label) {
|
||||
private static String deriveLogPrefix(String id) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("txn[");
|
||||
if (id != null) {
|
||||
sb.append(id);
|
||||
}
|
||||
sb.append("] ");
|
||||
if (label != null) {
|
||||
sb.append("label[").append(label).append("] ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.logPrefix = deriveLogPrefix(id,label);
|
||||
}
|
||||
|
||||
public String getLogPrefix() {
|
||||
return logPrefix;
|
||||
}
|
||||
@@ -518,14 +503,6 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error setting to readOnly?", e);
|
||||
}
|
||||
try {
|
||||
if (this.autoCommit) {
|
||||
// reset the autoCommit status prior to returning to pool
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error setting to readOnly?", e);
|
||||
}
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception ex) {
|
||||
@@ -541,16 +518,21 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* Notify the transaction manager.
|
||||
*/
|
||||
protected void notifyCommit() {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
if (queryOnly) {
|
||||
manager.notifyOfQueryOnly(true, this, null);
|
||||
} else {
|
||||
manager.notifyOfCommit(this);
|
||||
if (manager != null) {
|
||||
if (queryOnly) {
|
||||
manager.notifyOfQueryOnly(true, this, null);
|
||||
} else {
|
||||
manager.notifyOfCommit(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyQueryOnly() {
|
||||
if (manager != null) {
|
||||
manager.notifyOfQueryOnly(true, this, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback, Commit or Close for query only transaction.
|
||||
* <p>
|
||||
@@ -558,28 +540,56 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* rollback or just close the connection for performance.
|
||||
* </p>
|
||||
*/
|
||||
private void commitQueryOnly() {
|
||||
protected void connectionEndForQueryOnly() {
|
||||
try {
|
||||
switch (onQueryOnly) {
|
||||
case ROLLBACK:
|
||||
connection.rollback();
|
||||
performRollback();
|
||||
break;
|
||||
case COMMIT:
|
||||
connection.commit();
|
||||
performCommit();
|
||||
break;
|
||||
case CLOSE_ON_READCOMMITTED:
|
||||
// Connection is closed via deactivate() which follows
|
||||
// This optimisation is only available at READ COMMITTED Isolation
|
||||
// valid at READ COMMITTED Isolation
|
||||
break;
|
||||
default:
|
||||
connection.rollback();
|
||||
performRollback();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String m = "Error when ending a query only transaction via " + onQueryOnly;
|
||||
logger.error(m, e);
|
||||
logger.error("Error when ending a query only transaction via " + onQueryOnly, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual rollback on the connection.
|
||||
*/
|
||||
protected void performRollback() throws SQLException {
|
||||
connection.rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual commit on the connection.
|
||||
*/
|
||||
protected void performCommit() throws SQLException {
|
||||
connection.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* End the transaction on a query only request.
|
||||
*/
|
||||
public void endQueryOnly() {
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
connectionEndForQueryOnly();
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
deactivate();
|
||||
notifyQueryOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
*/
|
||||
@@ -590,13 +600,13 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
try {
|
||||
if (queryOnly) {
|
||||
// can rollback or just close for performance
|
||||
commitQueryOnly();
|
||||
connectionEndForQueryOnly();
|
||||
} else {
|
||||
// commit
|
||||
if (batchControl != null && !batchControl.isEmpty()) {
|
||||
batchControl.flush();
|
||||
}
|
||||
connection.commit();
|
||||
performCommit();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -613,13 +623,12 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
* Notify the transaction manager.
|
||||
*/
|
||||
protected void notifyRollback(Throwable cause) {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
if (queryOnly) {
|
||||
manager.notifyOfQueryOnly(false, this, cause);
|
||||
} else {
|
||||
manager.notifyOfRollback(this, cause);
|
||||
if (manager != null) {
|
||||
if (queryOnly) {
|
||||
manager.notifyOfQueryOnly(false, this, cause);
|
||||
} else {
|
||||
manager.notifyOfRollback(this, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +648,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
connection.rollback();
|
||||
performRollback();
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class TransactionManager {
|
||||
public static final Logger TXN_LOGGER = LoggerFactory.getLogger("org.avaje.ebean.TXN");
|
||||
|
||||
/**
|
||||
* The behaviour desired when ending a query only transaction.
|
||||
* The behavior desired when ending a query only transaction.
|
||||
*/
|
||||
public enum OnQueryOnly {
|
||||
|
||||
@@ -62,49 +62,47 @@ public class TransactionManager {
|
||||
COMMIT
|
||||
}
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
protected final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
/**
|
||||
* Prefix for transaction id's (logging).
|
||||
*/
|
||||
private final String prefix;
|
||||
protected final String prefix;
|
||||
|
||||
private final String externalTransPrefix;
|
||||
protected final String externalTransPrefix;
|
||||
|
||||
/**
|
||||
* The dataSource of connections.
|
||||
*/
|
||||
private final DataSource dataSource;
|
||||
protected final DataSource dataSource;
|
||||
|
||||
/**
|
||||
* Flag to indicate the default Isolation is READ COMMITTED. This enables us
|
||||
* to close queryOnly transactions rather than commit or rollback them.
|
||||
*/
|
||||
private final OnQueryOnly onQueryOnly;
|
||||
protected final OnQueryOnly onQueryOnly;
|
||||
|
||||
/**
|
||||
* The default batchMode for transactions.
|
||||
*/
|
||||
private final boolean defaultBatchMode;
|
||||
protected final boolean defaultBatchMode;
|
||||
|
||||
private final BackgroundExecutor backgroundExecutor;
|
||||
protected final BackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
protected final ClusterManager clusterManager;
|
||||
|
||||
//private final int commitDebugLevel;
|
||||
|
||||
private final String serverName;
|
||||
protected final String serverName;
|
||||
|
||||
/**
|
||||
* Id's for transaction logging.
|
||||
*/
|
||||
private AtomicLong transactionCounter = new AtomicLong(1000);
|
||||
protected AtomicLong transactionCounter = new AtomicLong(1000);
|
||||
|
||||
private int clusterDebugLevel;
|
||||
|
||||
private final BulkEventListenerMap bulkEventListenerMap;
|
||||
protected int clusterDebugLevel;
|
||||
|
||||
private TransactionEventListener[] transactionEventListeners;
|
||||
protected final BulkEventListenerMap bulkEventListenerMap;
|
||||
|
||||
protected TransactionEventListener[] transactionEventListeners;
|
||||
|
||||
/**
|
||||
* Create the TransactionManager
|
||||
@@ -130,7 +128,7 @@ public class TransactionManager {
|
||||
this.prefix = GlobalProperties.get("transaction.prefix", "");
|
||||
this.externalTransPrefix = GlobalProperties.get("transaction.prefix", "e");
|
||||
|
||||
String value = GlobalProperties.get("transaction.onqueryonly", "ROLLBACK").toUpperCase().trim();
|
||||
String value = GlobalProperties.get("transaction.onqueryonly", "CLOSE").toUpperCase().trim();
|
||||
this.onQueryOnly = getOnQueryOnly(value, dataSource);
|
||||
|
||||
initialiseHeartbeat();
|
||||
@@ -148,14 +146,14 @@ public class TransactionManager {
|
||||
((DataSourcePool)dataSource).shutdown(deregisterDriver);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public BulkEventListenerMap getBulkEventListenerMap() {
|
||||
return bulkEventListenerMap;
|
||||
}
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public BulkEventListenerMap getBulkEventListenerMap() {
|
||||
return bulkEventListenerMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the behaviour to use when a query only transaction is committed.
|
||||
@@ -171,7 +169,6 @@ public class TransactionManager {
|
||||
*/
|
||||
private OnQueryOnly getOnQueryOnly(String onQueryOnly, DataSource ds) {
|
||||
|
||||
|
||||
if (onQueryOnly.equals("COMMIT")){
|
||||
return OnQueryOnly.COMMIT;
|
||||
}
|
||||
@@ -222,26 +219,26 @@ public class TransactionManager {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster debug level.
|
||||
*/
|
||||
public int getClusterDebugLevel() {
|
||||
return clusterDebugLevel;
|
||||
}
|
||||
/**
|
||||
* Return the cluster debug level.
|
||||
*/
|
||||
public int getClusterDebugLevel() {
|
||||
return clusterDebugLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster debug level.
|
||||
*/
|
||||
public void setClusterDebugLevel(int clusterDebugLevel) {
|
||||
this.clusterDebugLevel = clusterDebugLevel;
|
||||
}
|
||||
/**
|
||||
* Set the cluster debug level.
|
||||
*/
|
||||
public void setClusterDebugLevel(int clusterDebugLevel) {
|
||||
this.clusterDebugLevel = clusterDebugLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the type of behaviour to use when closing a transaction that was used to query data only.
|
||||
*/
|
||||
public OnQueryOnly getOnQueryOnly() {
|
||||
return onQueryOnly;
|
||||
}
|
||||
/**
|
||||
* Defines the type of behavior to use when closing a transaction that was used to query data only.
|
||||
*/
|
||||
public OnQueryOnly getOnQueryOnly() {
|
||||
return onQueryOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the externally supplied Connection.
|
||||
@@ -276,7 +273,7 @@ public class TransactionManager {
|
||||
c = dataSource.getConnection();
|
||||
long id = transactionCounter.incrementAndGet();
|
||||
|
||||
JdbcTransaction t = new JdbcTransaction(prefix + id, explicit, c, this);
|
||||
SpiTransaction t = createTransaction(explicit, c, id);
|
||||
|
||||
// set the default batch mode. This can be on for
|
||||
// jdbc drivers that support getGeneratedKeys
|
||||
@@ -312,7 +309,7 @@ public class TransactionManager {
|
||||
c = dataSource.getConnection();
|
||||
long id = transactionCounter.incrementAndGet();
|
||||
|
||||
JdbcTransaction t = new JdbcTransaction(prefix + id, false, c, this);
|
||||
SpiTransaction t = createTransaction(false, c, id);
|
||||
|
||||
// set the default batch mode. Can be true for
|
||||
// jdbc drivers that support getGeneratedKeys
|
||||
@@ -339,6 +336,13 @@ public class TransactionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new transaction.
|
||||
*/
|
||||
protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) {
|
||||
return new JdbcTransaction(prefix + id, explicit, c, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a local rolled back transaction.
|
||||
*/
|
||||
@@ -429,9 +433,6 @@ public class TransactionManager {
|
||||
logger.error(m, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Process a Transaction that comes from another framework or local code.
|
||||
@@ -452,34 +453,33 @@ public class TransactionManager {
|
||||
|
||||
backgroundExecutor.execute(postCommit.notifyPersistListeners());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify local BeanPersistListeners etc of events from another server in the cluster.
|
||||
*/
|
||||
public void remoteTransactionEvent(RemoteTransactionEvent remoteEvent) {
|
||||
|
||||
if (clusterDebugLevel > 0 || logger.isDebugEnabled()){
|
||||
logger.info("Cluster Received: "+remoteEvent.toString());
|
||||
}
|
||||
|
||||
List<TableIUD> tableIUDList = remoteEvent.getTableIUDList();
|
||||
if (tableIUDList != null){
|
||||
for (int i = 0; i < tableIUDList.size(); i++) {
|
||||
TableIUD tableIUD = tableIUDList.get(i);
|
||||
beanDescriptorManager.cacheNotify(tableIUD);
|
||||
}
|
||||
}
|
||||
|
||||
List<BeanPersistIds> beanPersistList = remoteEvent.getBeanPersistList();
|
||||
if (beanPersistList != null){
|
||||
for (int i = 0; i < beanPersistList.size(); i++) {
|
||||
BeanPersistIds beanPersist = beanPersistList.get(i);
|
||||
beanPersist.notifyCacheAndListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify local BeanPersistListeners etc of events from another server in the cluster.
|
||||
*/
|
||||
public void remoteTransactionEvent(RemoteTransactionEvent remoteEvent) {
|
||||
|
||||
if (clusterDebugLevel > 0 || logger.isDebugEnabled()) {
|
||||
logger.info("Cluster Received: " + remoteEvent.toString());
|
||||
}
|
||||
|
||||
List<TableIUD> tableIUDList = remoteEvent.getTableIUDList();
|
||||
if (tableIUDList != null) {
|
||||
for (int i = 0; i < tableIUDList.size(); i++) {
|
||||
TableIUD tableIUD = tableIUDList.get(i);
|
||||
beanDescriptorManager.cacheNotify(tableIUD);
|
||||
}
|
||||
}
|
||||
|
||||
List<BeanPersistIds> beanPersistList = remoteEvent.getBeanPersistList();
|
||||
if (beanPersistList != null) {
|
||||
for (int i = 0; i < beanPersistList.size(); i++) {
|
||||
BeanPersistIds beanPersist = beanPersistList.get(i);
|
||||
beanPersist.notifyCacheAndListener();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.ebean;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
@@ -2,16 +2,18 @@ package com.avaje.ebeaninternal.server.querydefn;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
|
||||
public class TestQueryLanguage extends TestCase {
|
||||
public class TestQueryLanguage extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
DefaultOrmQuery<Order> q = check("find order join customer (id, name)");
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.tests.model.basic.UTDetail;
|
||||
|
||||
public class TestAutoCommitDataSource extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setName("h2autocommit");
|
||||
config.loadFromProperties();
|
||||
|
||||
config.addClass(UTDetail.class);
|
||||
config.setDdlGenerate(true);
|
||||
config.setDdlRun(true);
|
||||
config.setAutoCommitMode(true);
|
||||
|
||||
GlobalProperties.setSkipPrimaryServer(true);
|
||||
|
||||
EbeanServer ebeanServer = EbeanServerFactory.create(config);
|
||||
|
||||
|
||||
UTDetail detail1 = new UTDetail("one", 12, 30D);
|
||||
UTDetail detail2 = new UTDetail("two", 11, 30D);
|
||||
UTDetail detail3 = new UTDetail("three", 8, 30D);
|
||||
|
||||
Transaction txn = ebeanServer.beginTransaction();
|
||||
try {
|
||||
txn.setBatchMode(true);
|
||||
ebeanServer.save(detail1);
|
||||
ebeanServer.save(detail2);
|
||||
ebeanServer.save(detail3);
|
||||
txn.commit();
|
||||
|
||||
} finally {
|
||||
txn.end();
|
||||
}
|
||||
|
||||
List<UTDetail> details = ebeanServer.find(UTDetail.class).findList();
|
||||
Assert.assertEquals(3, details.size());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.util;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -14,6 +10,10 @@ import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* This ensures that the ClassPathSearch supports normal file:file.jar files as well as jar/war files
|
||||
* with bang paths. Bang paths typically look like this as a url:
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.avaje.tests.basic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.FutureList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.SqlFutureList;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.config.DataSourceConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
import com.avaje.tests.model.basic.ResetBasicData;
|
||||
import com.avaje.tests.model.basic.TOne;
|
||||
|
||||
public class MainFutureList {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
checkFutureRowCount(true);
|
||||
//testSqlQueryFuture();
|
||||
//testOrmFuture();
|
||||
}
|
||||
|
||||
public void executeDDL(EbeanServer server, String ddl) {
|
||||
|
||||
Transaction t = server.createTransaction();
|
||||
try {
|
||||
Connection connection = t.getConnection()
|
||||
;
|
||||
|
||||
|
||||
} finally {
|
||||
t.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void executeStmt(Connection c, String ddl) throws SQLException {
|
||||
java.sql.PreparedStatement pstmt = null;
|
||||
try {
|
||||
pstmt = c.prepareStatement(ddl);
|
||||
pstmt.execute();
|
||||
|
||||
} finally {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static EbeanServer createEbeanServer(boolean primary) {
|
||||
|
||||
if (primary){
|
||||
return Ebean.getServer(null);
|
||||
}
|
||||
|
||||
ServerConfig c = new ServerConfig();
|
||||
c.setName("pgtest");
|
||||
|
||||
// // requires postgres driver in class path
|
||||
// DataSourceConfig postgresDb = new DataSourceConfig();
|
||||
// postgresDb.setDriver("org.postgresql.Driver");
|
||||
// postgresDb.setUsername("test");
|
||||
// postgresDb.setPassword("test");
|
||||
// postgresDb.setUrl("jdbc:postgresql://127.0.0.1:5432/test");
|
||||
// postgresDb.setHeartbeatSql("select count(*) from t_one");
|
||||
|
||||
// requires oracle driver in class path
|
||||
DataSourceConfig oraDb = new DataSourceConfig();
|
||||
oraDb.setDriver("oracle.jdbc.driver.OracleDriver");
|
||||
oraDb.setUsername("junk");
|
||||
oraDb.setPassword("junk");
|
||||
oraDb.setUrl("jdbc:oracle:thin:junk/junk@localhost:1521:XE");
|
||||
oraDb.setHeartbeatSql("select count(*) from dual");
|
||||
|
||||
|
||||
c.loadFromProperties();
|
||||
c.setDdlGenerate(true);
|
||||
c.setDdlRun(true);
|
||||
c.setDefaultServer(false);
|
||||
c.setRegister(false);
|
||||
// c.setDataSourceConfig(postgresDb);
|
||||
c.setDataSourceConfig(oraDb);
|
||||
|
||||
//c.setDatabaseBooleanTrue("1");
|
||||
//c.setDatabaseBooleanFalse("0");
|
||||
//c.setDatabaseBooleanTrue("T");
|
||||
//c.setDatabaseBooleanFalse("F");
|
||||
|
||||
//c.setDatabasePlatform(new Postgres83Platform());
|
||||
|
||||
c.addClass(TOne.class);
|
||||
|
||||
return EbeanServerFactory.create(c);
|
||||
|
||||
}
|
||||
|
||||
public static void checkFutureRowCount(boolean primay) throws Exception {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
EbeanServer server = createEbeanServer(primay);
|
||||
|
||||
Query<Order> query = server.find(Order.class);
|
||||
Future<Integer> futureRowCount = server.findFutureRowCount(query, null);
|
||||
boolean done = futureRowCount.isDone();
|
||||
|
||||
System.out.println("done: "+done);
|
||||
|
||||
Integer rowCount = futureRowCount.get();
|
||||
System.out.println("got rc:"+rowCount);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void checkSqlQueryFuture(boolean primay) throws Exception {
|
||||
|
||||
EbeanServer server = createEbeanServer(primay);
|
||||
|
||||
String sql = "select o.* from all_tables o";
|
||||
SqlQuery sqlQuery = server.createSqlQuery(sql);
|
||||
|
||||
SqlFutureList list = server.findFutureList(sqlQuery, null);
|
||||
System.out.println("start done:"+list.isDone());
|
||||
Thread.sleep(200);
|
||||
if (!list.isDone()){
|
||||
list.cancel(true);
|
||||
}
|
||||
|
||||
if (!list.isCancelled()){
|
||||
List<SqlRow> list2 = list.get();
|
||||
System.out.println("got "+list2.size());
|
||||
}
|
||||
|
||||
Thread.sleep(3000);
|
||||
System.out.println("done sleeping");
|
||||
}
|
||||
|
||||
public static void checkOrmFuture() throws Exception {
|
||||
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
//EbeanServer server = Ebean.getServer(null);
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class);
|
||||
|
||||
FutureList<Order> futureList = query.findFutureList();
|
||||
|
||||
Thread.sleep(3000);
|
||||
System.out.println("end of sleep");
|
||||
|
||||
if (!futureList.isDone()){
|
||||
futureList.cancel(true);
|
||||
}
|
||||
|
||||
System.out.println("and... done:"+futureList.isDone());
|
||||
|
||||
if (!futureList.isCancelled()){
|
||||
//List<Order> l0 = futureList.get(30, TimeUnit.SECONDS);
|
||||
List<Order> list = futureList.get();
|
||||
System.out.println("list:"+list);
|
||||
}
|
||||
|
||||
System.out.println("done");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -21,7 +21,6 @@ public class TestErrorBindLog extends BaseTestCase {
|
||||
|
||||
} catch (PersistenceException e) {
|
||||
String msg = e.getMessage();
|
||||
e.printStackTrace();
|
||||
Assert.assertTrue(msg.contains("Bind values:"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.basic;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -4,8 +4,7 @@ import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.basic;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.tests.model.basic.Customer;
|
||||
import com.avaje.tests.model.basic.EBasicVer;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
@@ -20,9 +19,9 @@ public class TestLogTransLogOnError extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Transaction t = Ebean.beginTransaction();
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
// t.log("--- hello");
|
||||
|
||||
Ebean.find(Customer.class).findList();
|
||||
Ebean.find(Order.class).where().gt("id", 1).findList();
|
||||
|
||||
@@ -52,9 +51,8 @@ public class TestLogTransLogOnError extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Transaction t = Ebean.beginTransaction();
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
// t.log("--- hello testPersistError");
|
||||
Ebean.find(Customer.class).findList();
|
||||
|
||||
EBasicVer newBean = new EBasicVer();
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.basic;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.basic;
|
||||
import java.sql.Date;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.basic;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.basic;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -4,8 +4,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.basic.encrypt;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic.event;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.basic.one2one;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.tests.batchload;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.avaje.tests.batchload;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
@@ -57,7 +55,7 @@ public class TestBatchLazyWithDeleted extends BaseTestCase {
|
||||
Assert.assertEquals(1, deletedCount);
|
||||
|
||||
for (UUTwo u : list) {
|
||||
UUOne master = u.getMaster();
|
||||
u.getMaster();
|
||||
//BeanState beanState = Ebean.getBeanState(master);
|
||||
//Assert.assertTrue(beanState.isReference());
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.batchload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.batchload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -4,8 +4,7 @@ import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.batchload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -2,8 +2,7 @@ package com.avaje.tests.batchload;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.batchload;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
|
||||
+2
-2
@@ -1,7 +1,6 @@
|
||||
package com.avaje.tests.cache;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
@@ -31,6 +30,7 @@ public class TestCacheBasic extends BaseTestCase {
|
||||
ServerCacheStatistics statistics = countryCache.getStatistics(false);
|
||||
int hc = statistics.getHitCount();
|
||||
Assert.assertEquals(1, hc);
|
||||
Assert.assertNotNull(c0);
|
||||
|
||||
// Country c1 = Ebean.getReference(Country.class, "NZ");
|
||||
// Assert.assertEquals(2, countryCache.getStatistics(false).getHitCount());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user