mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eb54da2dc | ||
|
|
bb6ff866c7 | ||
|
|
2d719c5b37 | ||
|
|
9d54b264ad | ||
|
|
65b282a056 | ||
|
|
fc174c8988 | ||
|
|
06802896ef | ||
|
|
7f13ac9e5e | ||
|
|
4a1374d22d | ||
|
|
4ee8d647b7 | ||
|
|
59793f3c01 | ||
|
|
f7f383d8f3 | ||
|
|
562a3959b6 | ||
|
|
bb1275f4f9 | ||
|
|
7fde6b9331 | ||
|
|
3e97a4005a | ||
|
|
c271760230 | ||
|
|
f7c1845f0c | ||
|
|
9b04f20ed3 | ||
|
|
62b6b6293b | ||
|
|
6d8a1c9398 | ||
|
|
303039735f | ||
|
|
6bcf5c6881 | ||
|
|
0527f45f5a | ||
|
|
ba397bbb0c | ||
|
|
a617d58902 | ||
|
|
7fc4a229ae | ||
|
|
f53d31aa2e | ||
|
|
b889b6a6b0 | ||
|
|
f9b55a06b8 | ||
|
|
09d772a5e5 |
+2
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
@@ -50,7 +50,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.15</version>
|
||||
<version>7.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1671,7 +1671,7 @@ public interface ExpressionList<T> {
|
||||
ExpressionList<T> endAnd();
|
||||
|
||||
/**
|
||||
* End a AND junction - synonym for endJunction().
|
||||
* End a OR junction - synonym for endJunction().
|
||||
*/
|
||||
ExpressionList<T> endOr();
|
||||
|
||||
|
||||
@@ -59,6 +59,14 @@ public interface Transaction extends AutoCloseable {
|
||||
*/
|
||||
void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - turn on automatic persistence of dirty beans and batchMode true.
|
||||
* <p>
|
||||
* With this turned on beans that are dirty in the persistence context
|
||||
* are automatically persisted on flush() and commit().
|
||||
*/
|
||||
void setAutoPersistUpdates(boolean autoPersistUpdates);
|
||||
|
||||
/**
|
||||
* Set a label on the transaction.
|
||||
* <p>
|
||||
@@ -339,15 +347,12 @@ public interface Transaction extends AutoCloseable {
|
||||
* The batch is automatically flushed when it hits the batch size and also when we
|
||||
* execute queries or when we mix UpdateSql and CallableSql with save and delete of
|
||||
* beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* We use {@link #flush()} to explicitly flush the batch and we can use
|
||||
* {@link #setFlushOnQuery(boolean)} and {@link #setFlushOnMixed(boolean)}
|
||||
* to control the automatic flushing behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing of CallableSql executing every 10 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -392,14 +397,11 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* This only takes effect when batch mode on the transaction has not already meant that
|
||||
* JDBC batch mode is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
|
||||
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is effectively already turned on for all platforms apart from older Sql Server.
|
||||
* </p>
|
||||
*
|
||||
* @param batchMode the batch mode to use per save(), insert(), update() or delete()
|
||||
* @see io.ebean.config.DatabaseConfig#setPersistBatchOnCascade(PersistBatch)
|
||||
@@ -422,15 +424,19 @@ public interface Transaction extends AutoCloseable {
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* Specify if we want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
* By default batched inserts will try to use getGeneratedKeys if it is
|
||||
* supported by the underlying jdbc driver and database.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may want to turn getGeneratedKeys off when you are inserting a large
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
* We want to turn off getGeneratedKeys when we are inserting a large
|
||||
* number of objects and we don't care about getting back the ids. In this
|
||||
* way we avoid the extra cost of getting back the generated id values
|
||||
* from the database.
|
||||
* <p>
|
||||
* Note that when we do turn off getGeneratedKeys then we have the limitation
|
||||
* that after a bean has been inserted we are unable to then mutate the bean
|
||||
* and update it in the same transaction as we have not obtained it's id value.
|
||||
*/
|
||||
void setGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
@@ -449,13 +455,11 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* If you want to execute both WITHOUT having the batch automatically flush
|
||||
* you need to call this with batchFlushOnMixed = false.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
|
||||
* beans are executed). This is because the UpdateSql and CallableSql have
|
||||
* already been bound to their PreparedStatements. The beans on the other hand
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
void setFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
@@ -473,7 +477,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* <p>
|
||||
* Calling this method with batchFlushOnQuery = false means that you can
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
void setFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
@@ -490,7 +493,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* should be flushed prior to executing a query.
|
||||
* <p>
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
boolean isFlushOnQuery();
|
||||
|
||||
@@ -507,7 +509,6 @@ public interface Transaction extends AutoCloseable {
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
@@ -533,11 +534,9 @@ public interface Transaction extends AutoCloseable {
|
||||
* commit() rollback() and end() methods on the Transaction should still be
|
||||
* used. Calling these methods on the Connection would be a big no no unless
|
||||
* you know what you are doing.
|
||||
* </p>
|
||||
* <p>
|
||||
* Examples of when a developer may wish to use the connection directly are:
|
||||
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
|
||||
* </p>
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
@@ -545,17 +544,14 @@ public interface Transaction extends AutoCloseable {
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* Use this in conjunction with getConnection() and raw JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* This effectively informs Ebean of the data that has been changed by the
|
||||
* transaction and this information is normally automatically handled by Ebean
|
||||
* when you save entity beans or use UpdateSql etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you use raw JDBC then you can use this method to inform Ebean for the
|
||||
* tables that have been modified. Ebean uses this information to keep its
|
||||
* caches in synch and maintain text indexes.
|
||||
* </p>
|
||||
*/
|
||||
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.annotation.TxOption;
|
||||
import io.ebean.annotation.TxType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -33,6 +34,8 @@ public final class TxScope {
|
||||
|
||||
private TxIsolation isolation;
|
||||
|
||||
private TxOption autoPersistUpdates;
|
||||
|
||||
private PersistBatch batch;
|
||||
|
||||
private PersistBatch batchOnCascade;
|
||||
@@ -123,6 +126,13 @@ public final class TxScope {
|
||||
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the AutoPersistUpdates mode as a nullable Boolean.
|
||||
*/
|
||||
public Boolean getAutoPersistUpdates() {
|
||||
return autoPersistUpdates == null ? null : autoPersistUpdates.asBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
@@ -176,6 +186,14 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the autoPersistUpdates mode.
|
||||
*/
|
||||
public TxScope setAutoPersistUpdates(TxOption autoPersistUpdates) {
|
||||
this.autoPersistUpdates = autoPersistUpdates;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction profile id.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds entity beans by there type and id.
|
||||
* <p>
|
||||
@@ -77,6 +79,11 @@ public interface PersistenceContext {
|
||||
*/
|
||||
boolean resetLimit();
|
||||
|
||||
/**
|
||||
* Return the list of dirty beans held by this persistence context.
|
||||
*/
|
||||
List<Object> dirtyBeans();
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
* <p>
|
||||
|
||||
@@ -232,6 +232,12 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private String historyTableSuffix = "_history";
|
||||
|
||||
/**
|
||||
* When true explicit transactions beans that have been made dirty will be
|
||||
* automatically persisted via update on flush.
|
||||
*/
|
||||
private boolean autoPersistUpdates;
|
||||
|
||||
/**
|
||||
* Use for transaction scoped batch mode.
|
||||
*/
|
||||
@@ -905,6 +911,20 @@ public class DatabaseConfig {
|
||||
this.tenantCatalogProvider = tenantCatalogProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if dirty beans are automatically persisted.
|
||||
*/
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return autoPersistUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if dirty beans are automatically persisted.
|
||||
*/
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
this.autoPersistUpdates = autoPersistUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistBatch mode to use by default at the transaction level.
|
||||
* <p>
|
||||
@@ -2807,6 +2827,7 @@ public class DatabaseConfig {
|
||||
loadDocStoreSettings(p);
|
||||
|
||||
defaultServer = p.getBoolean("defaultServer", defaultServer);
|
||||
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
|
||||
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
|
||||
maxCallStack = p.getInt("maxCallStack", maxCallStack);
|
||||
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
|
||||
@@ -3348,7 +3369,7 @@ public class DatabaseConfig {
|
||||
this.loadModuleInfo = loadModuleInfo;
|
||||
}
|
||||
|
||||
public enum UuidVersion {
|
||||
public enum UuidVersion {
|
||||
VERSION4,
|
||||
VERSION1,
|
||||
VERSION1RND
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.8.1</tag>
|
||||
<tag>ebean-parent-12.8.3</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
@@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+17
-17
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -18,8 +18,8 @@
|
||||
<ebean-migration.version>12.4.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.1</ebean-test-docker.version>
|
||||
<ebean-datasource.version>7.0</ebean-datasource.version>
|
||||
<ebean-agent.version>12.8.1</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.8.1</ebean-maven-plugin.version>
|
||||
<ebean-agent.version>12.8.2</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.8.2</ebean-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -81,88 +81,88 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+7
-7
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.8.1</tag>
|
||||
<tag>ebean-parent-12.8.3</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -72,7 +72,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.8.4a</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -87,19 +87,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -302,7 +302,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -73,6 +73,10 @@ public class ScopeTrans {
|
||||
restoreBatchGeneratedKeys = transaction.getBatchGetGeneratedKeys();
|
||||
restoreBatchFlushOnQuery = transaction.isFlushOnQuery();
|
||||
}
|
||||
Boolean autoPersistUpdates = txScope.getAutoPersistUpdates();
|
||||
if (autoPersistUpdates != null) {
|
||||
transaction.setAutoPersistUpdates(autoPersistUpdates);
|
||||
}
|
||||
if (txScope.isBatchSet()) {
|
||||
transaction.setBatchMode(txScope.isBatchMode());
|
||||
}
|
||||
|
||||
@@ -147,6 +147,11 @@ public interface SpiTransaction extends Transaction {
|
||||
*/
|
||||
int depth();
|
||||
|
||||
/**
|
||||
* Return true if dirty beans are automatically persisted.
|
||||
*/
|
||||
boolean isAutoPersistUpdates();
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
|
||||
@@ -43,6 +43,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
return transaction.getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
transaction.setAutoPersistUpdates(autoPersistUpdates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return transaction.isAutoPersistUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitAndContinue() {
|
||||
transaction.commitAndContinue();
|
||||
|
||||
@@ -236,7 +236,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
this.clockService = config.getClockService();
|
||||
|
||||
DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this);
|
||||
this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor());
|
||||
this.transactionManager = config.createTransactionManager(this, docStoreComponents.updateProcessor());
|
||||
this.documentStore = docStoreComponents.documentStore();
|
||||
this.queryPlanManager = config.initQueryPlanManager(transactionManager);
|
||||
this.metaInfoManager = new DefaultMetaInfoManager(this);
|
||||
|
||||
@@ -23,6 +23,9 @@ import java.util.function.Predicate;
|
||||
*/
|
||||
public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
|
||||
private static final String ENC_PREFIX = EncryptAlias.PREFIX;
|
||||
private static final String ENC_PREFIX_UPPER = EncryptAlias.PREFIX.toUpperCase();
|
||||
|
||||
private final SpiDtoQuery<T> query;
|
||||
|
||||
private final DtoQueryEngine queryEngine;
|
||||
@@ -133,9 +136,9 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
static String parseColumn(String columnLabel) {
|
||||
if (columnLabel.startsWith("_e_") || columnLabel.startsWith("_E_")) {
|
||||
if (columnLabel.startsWith(ENC_PREFIX) || columnLabel.startsWith(ENC_PREFIX_UPPER)) {
|
||||
// encrypted column alias in the form _e_<tableAlias>_<column>
|
||||
final int pos = columnLabel.indexOf("_", 3);
|
||||
final int pos = columnLabel.indexOf("_", 4);
|
||||
if (pos > -1) {
|
||||
return columnLabel.substring(pos + 1);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
/**
|
||||
* Used to create column alias for encrypted columns.
|
||||
*/
|
||||
public interface EncryptAlias {
|
||||
String PREFIX = "zx__";
|
||||
}
|
||||
@@ -423,13 +423,13 @@ public class InternalConfiguration {
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) {
|
||||
TransactionManager createTransactionManager(SpiServer server, DocStoreUpdateProcessor indexUpdateProcessor) {
|
||||
|
||||
TransactionScopeManager scopeManager = createTransactionScopeManager();
|
||||
boolean notifyL2CacheInForeground = cacheManager.isLocalL2Caching() || config.isNotifyL2CacheInForeground();
|
||||
|
||||
TransactionManagerOptions options =
|
||||
new TransactionManagerOptions(notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor,
|
||||
new TransactionManagerOptions(server, notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor,
|
||||
indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager,
|
||||
tableModState, cacheNotify, clockService);
|
||||
|
||||
|
||||
@@ -887,6 +887,14 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove deleted beans from the persistence context early.
|
||||
*/
|
||||
public void removeFromPersistenceContext() {
|
||||
idValue = beanDescriptor.getId(entityBean);
|
||||
beanDescriptor.contextDeleted(transaction.getPersistenceContext(), idValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggressive L1 and L2 cache cleanup for deletes.
|
||||
*/
|
||||
@@ -1030,6 +1038,17 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
if (!publish) {
|
||||
beanDescriptor.setDraft(entityBean);
|
||||
}
|
||||
if (transaction.isAutoPersistUpdates() && idValue != null) {
|
||||
// with getGeneratedKeys off we will not have a idValue
|
||||
beanDescriptor.contextPut(transaction.getPersistenceContext(), idValue, entityBean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if persist can be skipped on the reference only bean.
|
||||
*/
|
||||
public boolean isSkipReference() {
|
||||
return intercept.isReference() || (Flags.isRecurse(flags) && beanDescriptor.referenceIdPropertyOnly(intercept));
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
|
||||
@@ -2473,7 +2473,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
* Return the property path given the db table and column.
|
||||
*/
|
||||
public String findBeanPath(String schemaName, String tableName, String columnName) {
|
||||
if (matchBaseTable(schemaName, tableName)) {
|
||||
if (matchBaseTable(tableName)) {
|
||||
return columnPath.get(columnName);
|
||||
}
|
||||
BeanPropertyAssoc<?> assocProperty = tablePath.get(tableName);
|
||||
@@ -2489,10 +2489,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean matchBaseTable(String schemaName, String tableName) {
|
||||
boolean matchBaseTable(String tableName) {
|
||||
return tableName.isEmpty()
|
||||
|| baseTable.equalsIgnoreCase(tableName)
|
||||
|| baseTable.equalsIgnoreCase(schemaName + "." + tableName);
|
||||
|| baseTable.endsWith("." + tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3134,7 +3134,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return ebi.isReference() || referenceIdPropertyOnly(ebi);
|
||||
}
|
||||
|
||||
boolean referenceIdPropertyOnly(EntityBeanIntercept ebi) {
|
||||
public boolean referenceIdPropertyOnly(EntityBeanIntercept ebi) {
|
||||
return idOnlyReference && ebi.hasIdOnly(idPropertyIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.core.EncryptAlias;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedWhenCreated;
|
||||
@@ -65,6 +66,8 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class);
|
||||
|
||||
private static final String ENC_PREFIX = " " + EncryptAlias.PREFIX;
|
||||
|
||||
/**
|
||||
* Flag to mark this is the id property.
|
||||
*/
|
||||
@@ -531,7 +534,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
* Return the SQL for the column including decryption function and column alias.
|
||||
*/
|
||||
private String getDecryptSqlWithColumnAlias(String tableAlias) {
|
||||
return dbEncryptFunction.getDecryptSql(tableAlias + "." + this.getDbColumn()) + " _e_" + tableAlias + "_" + this.getDbColumn();
|
||||
return dbEncryptFunction.getDecryptSql(tableAlias + "." + this.getDbColumn()) + ENC_PREFIX + tableAlias + "_" + this.getDbColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -81,18 +81,18 @@ class BeanPropertyAssocManySqlHelp<T> {
|
||||
|
||||
@Override
|
||||
public void visitOneImported(BeanPropertyAssocOne<?> p) {
|
||||
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitScalar(BeanProperty p) {
|
||||
public void visitScalar(BeanProperty p, boolean allowNonNull) {
|
||||
sb.append(",").append(p.getDbColumn());
|
||||
colCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -44,9 +44,11 @@ public abstract class BaseTablePropertyVisitor implements BeanPropertyVisitor {
|
||||
public abstract void visitOneImported(BeanPropertyAssocOne<?> p);
|
||||
|
||||
/**
|
||||
* Override this method for normal scalar property.
|
||||
* Override this method for normal scalar property. With allowNonNull
|
||||
* used with properties of Embedded beans that can only be Nonnull when
|
||||
* the Embedded bean is Nonnull.
|
||||
*/
|
||||
@Override
|
||||
public abstract void visitScalar(BeanProperty p);
|
||||
public abstract void visitScalar(BeanProperty p, boolean allowNonNull);
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -40,8 +40,8 @@ public interface BeanPropertyVisitor {
|
||||
void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded);
|
||||
|
||||
/**
|
||||
* Visit a scalar property.
|
||||
* Visit a scalar property specify allowing non-null (e.g. embedded bean scalar properties).
|
||||
*/
|
||||
void visitScalar(BeanProperty p);
|
||||
void visitScalar(BeanProperty p, boolean allowNonNull);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ public class VisitProperties {
|
||||
|
||||
} else {
|
||||
// simple scalar type
|
||||
pv.visitScalar(p);
|
||||
pv.visitScalar(p, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public final class BatchControl {
|
||||
*/
|
||||
private int bufferMax;
|
||||
|
||||
private Queue[] queues = new Queue[3];
|
||||
private final Queue[] queues = new Queue[3];
|
||||
|
||||
/**
|
||||
* Create for a given transaction, PersistExecute, default size and getGeneratedKeys.
|
||||
|
||||
@@ -447,7 +447,7 @@ public final class DefaultPersister implements Persister {
|
||||
public void insert(EntityBean bean, Transaction t) {
|
||||
|
||||
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
|
||||
if (req.isReference()) {
|
||||
if (req.isSkipReference()) {
|
||||
// skip insert on reference bean
|
||||
return;
|
||||
}
|
||||
@@ -881,6 +881,7 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
|
||||
int count = request.executeOrQueue();
|
||||
request.removeFromPersistenceContext();
|
||||
|
||||
if (request.isPersistCascade()) {
|
||||
deleteAssocOne(request);
|
||||
|
||||
+27
-4
@@ -1,11 +1,9 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
@@ -200,6 +198,20 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> dirtyBeans() {
|
||||
lock.lock();
|
||||
try {
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (ClassContext classContext : typeCache.values()) {
|
||||
classContext.dirtyBeans(list);
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
lock.lock();
|
||||
@@ -318,6 +330,17 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
deleteSet.add(id);
|
||||
map.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the dirty beans to the list.
|
||||
*/
|
||||
void dirtyBeans(List<Object> list) {
|
||||
for (Object value : map.values()) {
|
||||
if (((EntityBean) value)._ebean_getIntercept().isDirty()) {
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -95,6 +95,16 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
|
||||
return startNanos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLabel(String label) {
|
||||
// do nothing
|
||||
|
||||
@@ -187,6 +187,8 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
|
||||
private final long startNanos;
|
||||
|
||||
private boolean autoPersistUpdates;
|
||||
|
||||
/**
|
||||
* Create a new JdbcTransaction.
|
||||
*/
|
||||
@@ -209,11 +211,12 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
this.batchOnCascadeMode = false;
|
||||
this.onQueryOnly = OnQueryOnly.ROLLBACK;
|
||||
} else {
|
||||
this.autoPersistUpdates = explicit && manager.isAutoPersistUpdates();
|
||||
this.logSql = manager.isLogSql();
|
||||
this.logSummary = manager.isLogSummary();
|
||||
this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite();
|
||||
this.batchMode = manager.getPersistBatch();
|
||||
this.batchOnCascadeMode = manager.getPersistBatchOnCascade();
|
||||
this.batchMode = manager.isPersistBatch();
|
||||
this.batchOnCascadeMode = manager.isPersistBatchOnCascade();
|
||||
this.onQueryOnly = manager.getOnQueryOnly();
|
||||
}
|
||||
|
||||
@@ -294,6 +297,17 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
this.autoPersistUpdates = autoPersistUpdates;
|
||||
this.batchMode = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return autoPersistUpdates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipCacheExplicit() {
|
||||
return (skipCache != null && !skipCache);
|
||||
@@ -774,6 +788,10 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
* Flush the JDBC batch and execute derived relationship statements if necessary.
|
||||
*/
|
||||
private void internalBatchFlush() {
|
||||
if (autoPersistUpdates) {
|
||||
// Experimental - flush dirty beans held by the persistence context
|
||||
manager.flushTransparent(persistenceContext, this);
|
||||
}
|
||||
batchFlush();
|
||||
if (deferredList != null) {
|
||||
for (PersistDeferredRelationship deferred : deferredList) {
|
||||
@@ -1042,7 +1060,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
if (queryOnly) {
|
||||
if (queryOnly && !autoPersistUpdates) {
|
||||
connectionEndForQueryOnly();
|
||||
} else {
|
||||
flushCommitAndNotify();
|
||||
|
||||
@@ -25,6 +25,16 @@ class NoTransaction implements SpiTransaction {
|
||||
|
||||
static final NoTransaction INSTANCE = new NoTransaction();
|
||||
|
||||
@Override
|
||||
public void setAutoPersistUpdates(boolean autoPersistUpdates) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPersistUpdates() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLabel(String label) {
|
||||
// do nothing
|
||||
|
||||
+24
-3
@@ -5,6 +5,7 @@ import io.ebean.ProfileLocation;
|
||||
import io.ebean.TxScope;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxType;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.cache.ServerCacheNotification;
|
||||
import io.ebean.cache.ServerCacheNotify;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
@@ -17,6 +18,7 @@ import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.metric.MetricFactory;
|
||||
import io.ebean.metric.TimedMetric;
|
||||
import io.ebean.metric.TimedMetricMap;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebeaninternal.api.ScopeTrans;
|
||||
import io.ebeaninternal.api.ScopedTransaction;
|
||||
import io.ebeaninternal.api.SpiLogManager;
|
||||
@@ -59,6 +61,8 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
|
||||
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
|
||||
|
||||
private final SpiServer server;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
/**
|
||||
@@ -100,6 +104,8 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
*/
|
||||
final DocStoreUpdateProcessor docStoreUpdateProcessor;
|
||||
|
||||
private final boolean autoPersistUpdates;
|
||||
|
||||
private final boolean persistBatch;
|
||||
|
||||
private final boolean persistBatchOnCascade;
|
||||
@@ -153,7 +159,7 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
* Create the TransactionManager
|
||||
*/
|
||||
public TransactionManager(TransactionManagerOptions options) {
|
||||
|
||||
this.server = options.server;
|
||||
this.logManager = options.logManager;
|
||||
this.txnLogger = logManager.txn();
|
||||
this.txnDebug = txnLogger.isDebug();
|
||||
@@ -161,6 +167,7 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
this.supportsSavepointId = databasePlatform.isSupportsSavepointId();
|
||||
this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite();
|
||||
this.notifyL2CacheInForeground = options.notifyL2CacheInForeground;
|
||||
this.autoPersistUpdates = options.config.isAutoPersistUpdates();
|
||||
this.persistBatch = PersistBatch.ALL == options.config.getPersistBatch();
|
||||
this.persistBatchOnCascade = PersistBatch.ALL == options.config.appliedPersistBatchOnCascade();
|
||||
this.rollbackOnChecked = options.config.isTransactionRollbackOnChecked();
|
||||
@@ -279,11 +286,15 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
return bulkEventListenerMap;
|
||||
}
|
||||
|
||||
boolean getPersistBatch() {
|
||||
boolean isAutoPersistUpdates() {
|
||||
return autoPersistUpdates;
|
||||
}
|
||||
|
||||
boolean isPersistBatch() {
|
||||
return persistBatch;
|
||||
}
|
||||
|
||||
public boolean getPersistBatchOnCascade() {
|
||||
boolean isPersistBatchOnCascade() {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
@@ -786,4 +797,14 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
public boolean isLogSummary() {
|
||||
return logManager.sum().isDebug();
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental - find dirty beans in the persistence context and persist them.
|
||||
*/
|
||||
public void flushTransparent(PersistenceContext persistenceContext, SpiTransaction transaction) {
|
||||
List<Object> dirtyBeans = persistenceContext.dirtyBeans();
|
||||
if (!dirtyBeans.isEmpty()) {
|
||||
server.updateAll(dirtyBeans, transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.transaction;
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.cache.ServerCacheNotify;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebeaninternal.api.SpiLogManager;
|
||||
import io.ebeaninternal.api.SpiProfileHandler;
|
||||
import io.ebeaninternal.server.cluster.ClusterManager;
|
||||
@@ -15,6 +16,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
*/
|
||||
public class TransactionManagerOptions {
|
||||
|
||||
final SpiServer server;
|
||||
final boolean notifyL2CacheInForeground;
|
||||
final DatabaseConfig config;
|
||||
final ClusterManager clusterManager;
|
||||
@@ -31,11 +33,11 @@ public class TransactionManagerOptions {
|
||||
final ClockService clockService;
|
||||
|
||||
|
||||
public TransactionManagerOptions(boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager,
|
||||
public TransactionManagerOptions(SpiServer server, boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager,
|
||||
BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor,
|
||||
BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler,
|
||||
SpiLogManager logManager, TableModState tableModState, ServerCacheNotify cacheNotify, ClockService clockService) {
|
||||
|
||||
this.server = server;
|
||||
this.notifyL2CacheInForeground = notifyL2CacheInForeground;
|
||||
this.config = config;
|
||||
this.scopeManager = scopeManager;
|
||||
|
||||
@@ -149,6 +149,7 @@ public class ServerConfigTest {
|
||||
ServerConfig serverConfig = new ServerConfig();
|
||||
assertTrue(serverConfig.isIdGeneratorAutomatic());
|
||||
assertTrue(serverConfig.isDefaultServer());
|
||||
assertFalse(serverConfig.isAutoPersistUpdates());
|
||||
|
||||
serverConfig.setIdGeneratorAutomatic(false);
|
||||
assertFalse(serverConfig.isIdGeneratorAutomatic());
|
||||
@@ -166,6 +167,8 @@ public class ServerConfigTest {
|
||||
|
||||
serverConfig.setLoadModuleInfo(false);
|
||||
assertFalse(serverConfig.isAutoLoadModuleInfo());
|
||||
serverConfig.setAutoPersistUpdates(true);
|
||||
assertTrue(serverConfig.isAutoPersistUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -11,10 +11,10 @@ public class DtoQueryRequestTest {
|
||||
public void testParse() {
|
||||
|
||||
assertEquals("foo", DtoQueryRequest.parseColumn("foo"));
|
||||
assertEquals("bar", DtoQueryRequest.parseColumn("_e_t0_bar"));
|
||||
assertEquals("BAR", DtoQueryRequest.parseColumn("_E_T0_BAR"));
|
||||
assertEquals("baz", DtoQueryRequest.parseColumn("_e_t42_baz"));
|
||||
assertEquals("BAZ", DtoQueryRequest.parseColumn("_E_T42_BAZ"));
|
||||
assertEquals("bar", DtoQueryRequest.parseColumn("zx__t0_bar"));
|
||||
assertEquals("BAR", DtoQueryRequest.parseColumn("ZX__T0_BAR"));
|
||||
assertEquals("baz", DtoQueryRequest.parseColumn("zx__t42_baz"));
|
||||
assertEquals("BAZ", DtoQueryRequest.parseColumn("ZX__T42_BAZ"));
|
||||
|
||||
assertEquals("e_t42_nope", DtoQueryRequest.parseColumn("e_t42_nope"));
|
||||
assertEquals("_f_t42_nope", DtoQueryRequest.parseColumn("_f_t42_nope"));
|
||||
|
||||
@@ -4,21 +4,22 @@ import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebeaninternal.server.core.CacheOptions;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployIdentityMode;
|
||||
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Animal;
|
||||
import org.tests.model.basic.AnimalShelter;
|
||||
import org.tests.model.basic.Cat;
|
||||
import org.tests.model.basic.Contact;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Dog;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.*;
|
||||
import org.tests.model.bridge.BSite;
|
||||
import org.tests.model.bridge.BUser;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class BeanDescriptorTest extends BaseTestCase {
|
||||
|
||||
@@ -88,6 +89,42 @@ public class BeanDescriptorTest extends BaseTestCase {
|
||||
assertThat(props).extracting("name").contains("id", "status", "orderDate", "shipDate");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchBaseTable() {
|
||||
BeanDescriptor<Customer> desc = getBeanDescriptor(Customer.class);
|
||||
assertTrue(desc.matchBaseTable("o_customer"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchBaseTable_whenTableHasSchema_expect_matchRegardlessOfSchema() {
|
||||
|
||||
DeployBeanDescriptor<Customer> deploy = mockDeployCustomer();
|
||||
|
||||
when(deploy.getBaseTable()).thenReturn("foo.o_customer");
|
||||
BeanDescriptor<?> desc1 = new BeanDescriptor<>(mockOwner(), deploy);
|
||||
assertTrue(desc1.matchBaseTable("o_customer"));
|
||||
|
||||
when(deploy.getBaseTable()).thenReturn("bar.o_customer");
|
||||
BeanDescriptor<?> desc2 = new BeanDescriptor<>(mockOwner(), deploy);
|
||||
assertTrue(desc2.matchBaseTable("o_customer"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DeployBeanDescriptor<Customer> mockDeployCustomer() {
|
||||
DeployBeanDescriptor<Customer> deploy = mock(DeployBeanDescriptor.class);
|
||||
when(deploy.getBeanType()).thenReturn(Customer.class);
|
||||
when(deploy.getIdentityMode()).thenReturn(DeployIdentityMode.auto());
|
||||
when(deploy.buildIdentityMode()).thenReturn(IdentityMode.NONE);
|
||||
when(deploy.getCacheOptions()).thenReturn(CacheOptions.NO_CACHING);
|
||||
return deploy;
|
||||
}
|
||||
|
||||
private BeanDescriptorMap mockOwner() {
|
||||
BeanDescriptorMap owner = mock(BeanDescriptorMap.class);
|
||||
when(owner.createDocStoreBeanAdapter(any(), any())).thenReturn(mock(DocStoreBeanAdapter.class));
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void merge_when_empty() {
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ public class PersonCacheEmail {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public PersonCacheEmail(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.tests.cache.personinfo;
|
||||
|
||||
import io.ebean.annotation.WhenCreated;
|
||||
import io.ebean.annotation.WhenModified;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
public class PersonOther {
|
||||
|
||||
@Id
|
||||
@Size(max=128)
|
||||
private String id;
|
||||
|
||||
private String email;
|
||||
|
||||
@WhenCreated
|
||||
private Instant whenCreated;
|
||||
|
||||
@WhenModified
|
||||
private Instant whenModified;
|
||||
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
public PersonOther(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Instant getWhenCreated() {
|
||||
return whenCreated;
|
||||
}
|
||||
|
||||
public void setWhenCreated(Instant whenCreated) {
|
||||
this.whenCreated = whenCreated;
|
||||
}
|
||||
|
||||
public Instant getWhenModified() {
|
||||
return whenModified;
|
||||
}
|
||||
|
||||
public void setWhenModified(Instant whenModified) {
|
||||
this.whenModified = whenModified;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.tests.cache.personinfo;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestStringIdOnly extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
|
||||
PersonCacheEmail b0 = new PersonCacheEmail("IdOnly");
|
||||
DB.save(b0);
|
||||
|
||||
PersonCacheEmail found = DB.find(PersonCacheEmail.class, b0.getId());
|
||||
assertThat(found).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insert_whenIdOnly() {
|
||||
|
||||
PersonOther b0 = new PersonOther("IdOnly");
|
||||
DB.save(b0);
|
||||
|
||||
PersonOther found = DB.find(PersonOther.class, b0.getId());
|
||||
assertThat(found).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
package org.tests.model.embedded;
|
||||
|
||||
import io.ebean.annotation.NotNull;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import java.util.Date;
|
||||
|
||||
@Embeddable
|
||||
public class EEmbDatePeriod {
|
||||
|
||||
@NotNull
|
||||
Date date1;
|
||||
@NotNull
|
||||
Date date2;
|
||||
|
||||
public Date getDate1() {
|
||||
|
||||
@@ -31,7 +31,7 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
runQueries();
|
||||
|
||||
StringBuilder buffer0 = new StringBuilder();
|
||||
server().getMetaInfoManager()
|
||||
DB.getDefault().getMetaInfoManager()
|
||||
.collectMetricsAsJson()
|
||||
.withHeader(false)
|
||||
.write(buffer0);
|
||||
@@ -45,7 +45,7 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
runQueries();
|
||||
|
||||
StringBuilder buffer1 = new StringBuilder();
|
||||
server().getMetaInfoManager()
|
||||
DB.getDefault().getMetaInfoManager()
|
||||
.collectMetricsAsJson()
|
||||
.withHeader(false)
|
||||
.write(buffer1);
|
||||
@@ -55,7 +55,6 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
assertThat(json1).contains("\"name\":\"txn.main\"");
|
||||
assertThat(json1).contains("\"name\":\"orm.Customer.findList\"");
|
||||
assertThat(json1).doesNotContain("\"sql\":\"select t0.id, t0.status, t0.name");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -85,7 +84,6 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
assertThat(customer.getName()).isEqualTo(customer1.getName());
|
||||
|
||||
assertThat(Customer.find.db().getName()).isEqualTo(DB.getDefault().getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,7 +176,7 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
// change default collect query plan threshold to 200 micros
|
||||
QueryPlanInit init0 = new QueryPlanInit();
|
||||
init0.setAll(true);
|
||||
init0.setThresholdMicros(200);
|
||||
init0.setThresholdMicros(2);
|
||||
final List<MetaQueryPlan> plans = server().getMetaInfoManager().queryPlanInit(init0);
|
||||
assertThat(plans.size()).isGreaterThan(1);
|
||||
|
||||
@@ -188,14 +186,14 @@ public class TestCustomerFinder extends BaseTestCase {
|
||||
// change query plan threshold to 100 micros
|
||||
QueryPlanInit init = new QueryPlanInit();
|
||||
init.setAll(true);
|
||||
init.setThresholdMicros(100);
|
||||
init.setThresholdMicros(1);
|
||||
final List<MetaQueryPlan> appliedToPlans = server().getMetaInfoManager().queryPlanInit(init);
|
||||
assertThat(appliedToPlans.size()).isGreaterThan(4);
|
||||
|
||||
// run queries again
|
||||
runQueries();
|
||||
|
||||
ServerMetrics metrics = server().getMetaInfoManager().collectMetrics();
|
||||
ServerMetrics metrics = DB.getDefault().getMetaInfoManager().collectMetrics();
|
||||
|
||||
List<MetaQueryMetric> planStats = metrics.getQueryMetrics();
|
||||
assertThat(planStats.size()).isGreaterThan(4);
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
package org.tests.rawsql;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.RawSqlBuilder;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestRawSqlPositionedParams extends BaseTestCase {
|
||||
|
||||
private static final RawSql RAWSQL_1 = RawSqlBuilder
|
||||
.parse("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?")
|
||||
.create();
|
||||
|
||||
private static final RawSql RAW_SQL_2 = RawSqlBuilder
|
||||
.unparsed("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?")
|
||||
.columnMapping("r.id", "id")
|
||||
.columnMapping("r.name", "name")
|
||||
.create();
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
RawSql rawSql = RawSqlBuilder
|
||||
.parse("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?")
|
||||
.create();
|
||||
List<Customer> list = DB.find(Customer.class)
|
||||
.setRawSql(RAWSQL_1)
|
||||
.setParameter(1)
|
||||
.setParameter("R%")
|
||||
.where().lt("id", 2001)
|
||||
.findList();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class);
|
||||
query.setRawSql(rawSql);
|
||||
query.setParameter(1, 1);
|
||||
query.setParameter(2, "R%");
|
||||
query.where().lt("id", 2001);
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
|
||||
assertNotNull(list);
|
||||
assertThat(list).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -40,18 +44,12 @@ public class TestRawSqlPositionedParams extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
RawSql rawSql = RawSqlBuilder
|
||||
.unparsed("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?")
|
||||
.columnMapping("r.id", "id")
|
||||
.columnMapping("r.name", "name").create();
|
||||
List<Customer> list = DB.find(Customer.class)
|
||||
.setRawSql(RAW_SQL_2)
|
||||
.setParameter(1)
|
||||
.setParameter("R%")
|
||||
.findList();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class);
|
||||
query.setRawSql(rawSql);
|
||||
query.setParameter(1, 1);
|
||||
query.setParameter(2, "R%");
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
|
||||
assertNotNull(list);
|
||||
assertThat(list).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
package org.tests.rawsql;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.RawSqlBuilder;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestRawSqlUnparsedQuery extends BaseTestCase {
|
||||
|
||||
private static final RawSql rawSql = RawSqlBuilder
|
||||
.unparsed("select r.id, r.name from o_customer r where r.id >= :a and r.name like :b")
|
||||
.columnMapping("r.id", "id")
|
||||
.columnMapping("r.name", "name")
|
||||
.create();
|
||||
|
||||
@Test
|
||||
public void testDoubleUnparsedQuery() {
|
||||
|
||||
@@ -25,17 +31,14 @@ public class TestRawSqlUnparsedQuery extends BaseTestCase {
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
RawSql rawSql = RawSqlBuilder
|
||||
.unparsed("select r.id, r.name from o_customer r where r.id >= :a and r.name like :b")
|
||||
.columnMapping("r.id", "id").columnMapping("r.name", "name").create();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class);
|
||||
query.setRawSql(rawSql);
|
||||
query.setParameter("a", 1);
|
||||
query.setParameter("b", "R%");
|
||||
List<Customer> list = DB.find(Customer.class)
|
||||
.setRawSql(rawSql)
|
||||
.setParameter("a", 1)
|
||||
.setParameter("b", "R%")
|
||||
.findList();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
Assert.assertNotNull(list);
|
||||
assertThat(list).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
package org.tests.transparentpersist;
|
||||
|
||||
import io.ebean.*;
|
||||
import io.ebean.annotation.*;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeantest.LoggedSql;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.basic.Order;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestTransparentPersist extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void insertFlush_mutateFlush_expect_update() {
|
||||
|
||||
LoggedSql.start();
|
||||
|
||||
EBasicVer newBean;
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
newBean = new EBasicVer("insertMe");
|
||||
DB.save(newBean);
|
||||
|
||||
// flush - new bean needs to get registered into persistence context
|
||||
transaction.flush();
|
||||
|
||||
// make it dirty, we expect it to execute an update on flush()
|
||||
newBean.setName("make it dirty - auto save");
|
||||
|
||||
// flush again, auto persist dirty bean in persistence context
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
|
||||
EBasicVer found = DB.find(EBasicVer.class, newBean.getId());
|
||||
assertThat(found.getName()).isEqualTo("make it dirty - auto save");
|
||||
|
||||
assertThat(sql).hasSize(4);
|
||||
assertThat(sql.get(0)).contains("insert into e_basicver");
|
||||
assertThat(sql.get(1)).contains(" -- bind(");
|
||||
assertThat(sql.get(2)).contains("update e_basicver set name=?, last_update=? where id=? and last_update=?");
|
||||
assertThat(sql.get(3)).contains(" -- bind(");
|
||||
|
||||
DB.delete(found);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_expect_beanRemovedFromPersistenceContext() {
|
||||
|
||||
EBasicVer b0 = new EBasicVer("simpleDelete");
|
||||
DB.save(b0);
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
EBasicVer found = DB.find(EBasicVer.class, b0.getId());
|
||||
// make it dirty
|
||||
found.setName("make it dirty");
|
||||
|
||||
// delete it, should remove it from the "live" part of persistence context
|
||||
// with the expectation that no update is executed (no dirty in PC update)
|
||||
DB.delete(found);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class, b0.getId());
|
||||
assertThat(after).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleInsertUpdateDelete_experimental() {
|
||||
|
||||
EBasicVer b0 = new EBasicVer("simpleIUD_0");
|
||||
b0.save();
|
||||
EBasicVer b1 = new EBasicVer("simpleIUD_1");
|
||||
b1.save();
|
||||
EBasicVer b2 = new EBasicVer("simpleIUD_2");
|
||||
b2.save();
|
||||
|
||||
EBasicVer newBean;
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
EBasicVer found = DB.find(EBasicVer.class, b0.getId());
|
||||
found.setName("auto dirty");
|
||||
|
||||
// delete by id
|
||||
DB.delete(EBasicVer.class, b1.getId());
|
||||
// find and delete, note the delete is batched up to execute later
|
||||
DB.delete(DB.find(EBasicVer.class, b2.getId()));
|
||||
|
||||
// insert is batched up to execute later
|
||||
newBean = new EBasicVer("simpleIUD_New1");
|
||||
DB.save(newBean);
|
||||
// can still mutate newBean before flush (but not after flush yet as new bean isn't put into Persistence context)
|
||||
newBean.setName("simpleIUD_New2");
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class, b0.getId());
|
||||
assertThat(after.getName()).isEqualTo("auto dirty");
|
||||
|
||||
EBasicVer wasInserted = DB.find(EBasicVer.class, newBean.getId());
|
||||
assertThat(wasInserted.getName()).isEqualTo("simpleIUD_New2");
|
||||
|
||||
assertThat(DB.find(EBasicVer.class, b1.getId())).isNull();
|
||||
assertThat(DB.find(EBasicVer.class, b2.getId())).isNull();
|
||||
|
||||
DB.delete(after);
|
||||
DB.delete(wasInserted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleUpdate_experimental() {
|
||||
|
||||
EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate");
|
||||
transPersist.save();
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
EBasicVer found = DB.find(EBasicVer.class, transPersist.getId());
|
||||
found.setName("Persisted automatically as dirty");
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class,transPersist.getId());
|
||||
assertThat(after.getName()).isEqualTo("Persisted automatically as dirty");
|
||||
DB.delete(after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateWithPersistCascadeInsert() {
|
||||
|
||||
// setup data
|
||||
Customer c0 = new Customer();
|
||||
c0.setName("firstCust");
|
||||
Order order = new Order();
|
||||
order.setStatus(Order.Status.NEW);
|
||||
order.setCustomer(c0);
|
||||
DB.save(order);
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
Order foundOrder = DB.find(Order.class, order.getId());
|
||||
foundOrder.setStatus(Order.Status.APPROVED);
|
||||
// cascade persist will insert this customer (even though it isn't in the persistence context)
|
||||
Customer c1 = new Customer();
|
||||
c1.setName("newCust CascadePersist");
|
||||
foundOrder.setCustomer(c1);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
Order checkOrder = DB.find(Order.class, order.getId());
|
||||
|
||||
assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.APPROVED);
|
||||
assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist");
|
||||
|
||||
DB.delete(checkOrder);
|
||||
DB.delete(Customer.class, checkOrder.getCustomer().getId());
|
||||
DB.delete(Customer.class, c0.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateReferenceOnlyWithPersistCascade_Insert_andUpdateForeignKey() {
|
||||
|
||||
// setup data
|
||||
Customer c0 = new Customer();
|
||||
c0.setName("firstCust");
|
||||
Order order = new Order();
|
||||
order.setStatus(Order.Status.NEW);
|
||||
order.setCustomer(c0);
|
||||
DB.save(order);
|
||||
|
||||
LoggedSql.start();
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
|
||||
|
||||
Order foundOrder = DB.find(Order.class, order.getId());
|
||||
// we ONLY mutate the foreign key
|
||||
// cascade persist will insert this customer (even though it isn't in the persistence context)
|
||||
Customer c1 = new Customer();
|
||||
c1.setName("newCust CascadePersist");
|
||||
foundOrder.setCustomer(c1);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
|
||||
Order checkOrder = DB.find(Order.class, order.getId());
|
||||
|
||||
assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW);
|
||||
assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist");
|
||||
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date");
|
||||
assertThat(sql.get(1)).contains("insert into o_customer");
|
||||
assertThat(sql.get(2)).contains(" -- bind(");
|
||||
assertThat(sql.get(3)).contains("update o_order set updtime=?, kcustomer_id=? where id=? and updtime=?");
|
||||
assertThat(sql.get(4)).contains(" -- bind(");
|
||||
|
||||
DB.delete(checkOrder);
|
||||
DB.delete(Customer.class, checkOrder.getCustomer().getId());
|
||||
DB.delete(Customer.class, c0.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void txScope_setAutoPersistUpdates() {
|
||||
|
||||
EBasicVer b0 = new EBasicVer("txScopeUpdate");
|
||||
b0.save();
|
||||
|
||||
DB.execute(TxScope.required().setAutoPersistUpdates(TxOption.ON), () -> {
|
||||
EBasicVer found = DB.find(EBasicVer.class, b0.getId());
|
||||
found.setName("mutable txScope bean");
|
||||
});
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class, b0.getId());
|
||||
assertThat(after.getName()).isEqualTo("mutable txScope bean");
|
||||
|
||||
DB.delete(after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void txn_setAutoPersistUpdates() {
|
||||
|
||||
EBasicVer b0 = new EBasicVer("txn autoPersistUpdates ON");
|
||||
b0.save();
|
||||
|
||||
performUpdate(b0);
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class, b0.getId());
|
||||
assertThat(after.getName()).isEqualTo("mutated with autoPersistUpdates ON");
|
||||
|
||||
DB.delete(after);
|
||||
}
|
||||
|
||||
@Transactional(autoPersistUpdates = TxOption.ON)
|
||||
private void performUpdate(EBasicVer b0) {
|
||||
EBasicVer found = DB.find(EBasicVer.class, b0.getId());
|
||||
found.setName("mutated with autoPersistUpdates ON");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simulate_transparentPersistence_forSimpleUpdate() {
|
||||
|
||||
EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate");
|
||||
transPersist.save();
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(10);
|
||||
|
||||
EBasicVer found = DB.find(EBasicVer.class, transPersist.getId());
|
||||
found.setName("Changed");
|
||||
|
||||
// simulate transparent persistence
|
||||
List<Object> dirtyBeans = simulateTransparentPersist(transaction);
|
||||
assertThat(dirtyBeans).hasSize(1);
|
||||
assertThat(dirtyBeans).contains(found);
|
||||
|
||||
// would occur as first part of flush
|
||||
transaction.flush();
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
EBasicVer after = DB.find(EBasicVer.class,transPersist.getId());
|
||||
assertThat(after.getName()).isEqualTo("Changed");
|
||||
DB.delete(after);
|
||||
}
|
||||
|
||||
private List<Object> simulateTransparentPersist(Transaction transaction) {
|
||||
Database db = DB.getDefault();
|
||||
List<Object> dirtyBeans = getDirtyBeansFromPersistenceContext(transaction);
|
||||
for (Object dirtyBean : dirtyBeans) {
|
||||
db.update(dirtyBean, transaction);
|
||||
}
|
||||
return dirtyBeans;
|
||||
}
|
||||
|
||||
private List<Object> getDirtyBeansFromPersistenceContext(Transaction transaction) {
|
||||
return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean ddl generation</name>
|
||||
@@ -28,14 +28,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
+4
-4
@@ -175,7 +175,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
if (p instanceof BeanPropertyAssocOne) {
|
||||
visitOneImported((BeanPropertyAssocOne<?>)p);
|
||||
} else {
|
||||
visitScalar(p);
|
||||
// only allow Nonnull if embedded is Nonnull
|
||||
visitScalar(p, !embedded.isNullable());
|
||||
}
|
||||
if (embedded.isId()) {
|
||||
// compound primary key
|
||||
@@ -259,8 +260,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitScalar(BeanProperty p) {
|
||||
|
||||
public void visitScalar(BeanProperty p, boolean allowNonNull) {
|
||||
if (p.isSecondaryTable()) {
|
||||
lastColumn = null;
|
||||
return;
|
||||
@@ -292,7 +292,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
}
|
||||
} else {
|
||||
col.setDefaultValue(p.getDbColumnDefault());
|
||||
if (!p.isNullable() || p.isDDLNotNull()) {
|
||||
if (allowNonNull && (!p.isNullable() || p.isDDLNotNull())) {
|
||||
col.setNotnull(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean external mapping api</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.8.1</tag>
|
||||
<tag>ebean-parent-12.8.3</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean external mapping xml</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -59,14 +59,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean postgis</name>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean querybean</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -57,21 +57,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -24,4 +24,70 @@ public class PInteger<R> extends PBaseNumber<R,Integer> {
|
||||
super(name, root, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Flags Bulk + Size = Size
|
||||
* // ... meaning Bulk is not set and Size is set
|
||||
*
|
||||
* int selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
|
||||
* int mask = BwFlags.HAS_SIZE; // Only Size flag set
|
||||
*
|
||||
* bitwiseAnd(selectedFlags, mask)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAnd(int flags, int mask) {
|
||||
expr().bitwiseAnd(_name, flags, mask);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAll(int flags) {
|
||||
expr().bitwiseAll(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAny(int flags) {
|
||||
expr().bitwiseAny(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for the given bit flags to be NOT set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseNot(BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseNot(int flags) {
|
||||
expr().bitwiseNot(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ package io.ebean.typequery;
|
||||
*
|
||||
* @param <R> the root query bean type
|
||||
*/
|
||||
public class PLong<R> extends PBaseNumber<R,Long> {
|
||||
public class PLong<R> extends PBaseNumber<R, Long> {
|
||||
|
||||
/**
|
||||
* Construct with a property name and root instance.
|
||||
@@ -14,7 +14,7 @@ public class PLong<R> extends PBaseNumber<R,Long> {
|
||||
* @param root the root query bean instance
|
||||
*/
|
||||
public PLong(String name, R root) {
|
||||
super(name , root);
|
||||
super(name, root);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,4 +24,70 @@ public class PLong<R> extends PBaseNumber<R,Long> {
|
||||
super(name, root, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Flags Bulk + Size = Size
|
||||
* // ... meaning Bulk is not set and Size is set
|
||||
*
|
||||
* long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
|
||||
* long mask = BwFlags.HAS_SIZE; // Only Size flag set
|
||||
*
|
||||
* bitwiseAnd(selectedFlags, mask)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAnd(long flags, long mask) {
|
||||
expr().bitwiseAnd(_name, flags, mask);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAll(long flags) {
|
||||
expr().bitwiseAll(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAny(long flags) {
|
||||
expr().bitwiseAny(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for the given bit flags to be NOT set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseNot(BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseNot(long flags) {
|
||||
expr().bitwiseNot(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ package io.ebean.typequery;
|
||||
*
|
||||
* @param <R> the root query bean type
|
||||
*/
|
||||
public class PShort<R> extends PBaseNumber<R,Short> {
|
||||
public class PShort<R> extends PBaseNumber<R, Short> {
|
||||
|
||||
/**
|
||||
* Construct with a property name and root instance.
|
||||
@@ -24,4 +24,70 @@ public class PShort<R> extends PBaseNumber<R,Short> {
|
||||
super(name, root, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Flags Bulk + Size = Size
|
||||
* // ... meaning Bulk is not set and Size is set
|
||||
*
|
||||
* short selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
|
||||
* short mask = BwFlags.HAS_SIZE; // Only Size flag set
|
||||
*
|
||||
* bitwiseAnd(selectedFlags, mask)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAnd(short flags, short mask) {
|
||||
expr().bitwiseAnd(_name, flags, mask);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ALL of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAll(short flags) {
|
||||
expr().bitwiseAll(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for ANY of the given bit flags to be set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseAny(short flags) {
|
||||
expr().bitwiseAny(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expression for the given bit flags to be NOT set.
|
||||
* <pre>{@code
|
||||
*
|
||||
* bitwiseNot(BwFlags.HAS_COLOUR)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param flags The flags we are looking for
|
||||
*/
|
||||
public R bitwiseNot(short flags) {
|
||||
expr().bitwiseNot(_name, flags);
|
||||
return _root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package io.ebean.typequery;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* ZonedDateTime property.
|
||||
*
|
||||
* @param <R> the root query bean type
|
||||
*/
|
||||
public class PZonedDateTime<R> extends PBaseCompareable<R, ZonedDateTime> {
|
||||
|
||||
/**
|
||||
* Construct with a property name and root instance.
|
||||
*
|
||||
* @param name property name
|
||||
* @param root the root query bean instance
|
||||
*/
|
||||
public PZonedDateTime(String name, R root) {
|
||||
super(name, root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with additional path prefix.
|
||||
*/
|
||||
public PZonedDateTime(String name, R root, String prefix) {
|
||||
super(name, root, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as greater than.
|
||||
*
|
||||
* @param value the equal to bind value
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
public R after(ZonedDateTime value) {
|
||||
expr().gt(_name, value);
|
||||
return _root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as less than.
|
||||
*
|
||||
* @param value the equal to bind value
|
||||
* @return the root query bean instance
|
||||
*/
|
||||
public R before(ZonedDateTime value) {
|
||||
expr().lt(_name, value);
|
||||
return _root;
|
||||
}
|
||||
}
|
||||
@@ -679,7 +679,7 @@ public abstract class TQRootBean<T, R> {
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
R withLock(Query.LockType lockType) {
|
||||
public R withLock(Query.LockType lockType) {
|
||||
query.withLock(lockType);
|
||||
return root;
|
||||
}
|
||||
@@ -693,7 +693,7 @@ public abstract class TQRootBean<T, R> {
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
R withLock(Query.LockType lockType, Query.LockWait lockWait) {
|
||||
public R withLock(Query.LockType lockType, Query.LockWait lockWait) {
|
||||
query.withLock(lockType, lockWait);
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.example.domain;
|
||||
import io.ebean.annotation.DbArray;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -11,33 +12,35 @@ import java.util.Map;
|
||||
* Contact entity bean.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="be_contact")
|
||||
@Table(name = "be_contact")
|
||||
public class Contact extends BaseModel {
|
||||
|
||||
@DbArray
|
||||
List<String> phoneNumbers = new ArrayList();
|
||||
List<String> phoneNumbers = new ArrayList<>();
|
||||
|
||||
@Column(length=50)
|
||||
@Column(length = 50)
|
||||
String firstName;
|
||||
|
||||
@Column(length=50)
|
||||
@Column(length = 50)
|
||||
String lastName;
|
||||
|
||||
@Column(length=200)
|
||||
@Column(length = 200)
|
||||
String email;
|
||||
|
||||
@Column(length=20)
|
||||
@Column(length = 20)
|
||||
String phone;
|
||||
|
||||
@ManyToOne(optional=false)
|
||||
ZonedDateTime zoneDateTime;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
Customer customer;
|
||||
|
||||
@OneToMany(mappedBy = "contact")
|
||||
List<ContactNote> notes;
|
||||
|
||||
@OneToMany(cascade = CascadeType.PERSIST)
|
||||
@MapKey(name="key")
|
||||
Map<String,ContactOther> others;
|
||||
@MapKey(name = "key")
|
||||
Map<String, ContactOther> others;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
@@ -85,6 +88,14 @@ public class Contact extends BaseModel {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public ZonedDateTime getZoneDateTime() {
|
||||
return zoneDateTime;
|
||||
}
|
||||
|
||||
public void setZoneDateTime(ZonedDateTime zoneDateTime) {
|
||||
this.zoneDateTime = zoneDateTime;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,15 @@ package org.querytest;
|
||||
import org.example.domain.query.QContact;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class QContactTest {
|
||||
|
||||
@Test
|
||||
public void test_oneToManyMap() {
|
||||
|
||||
new QContact()
|
||||
.others.fetch()
|
||||
.zoneDateTime.before(ZonedDateTime.now())
|
||||
.findList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ public class QCustomerTest {
|
||||
// not found using other transaction
|
||||
final Customer foundNot = new QCustomer()
|
||||
.name.eq("explicitTransaction")
|
||||
.withLock(Query.LockType.SHARE)
|
||||
.findOne();
|
||||
assertThat(foundNot).isNull();
|
||||
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
@@ -22,35 +22,35 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean test</name>
|
||||
@@ -29,14 +29,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean composite</name>
|
||||
@@ -22,20 +22,20 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Technically optional but most expected to use query beans -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>kotlin querybean generator</name>
|
||||
@@ -29,7 +29,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
+2
-4
@@ -25,10 +25,9 @@ class PropertyTypeMap {
|
||||
*/
|
||||
private final PropertyType dbJsonType = new PropertyType("PJson");
|
||||
|
||||
private Map<String,PropertyType> map = new HashMap<>();
|
||||
private final Map<String,PropertyType> map = new HashMap<>();
|
||||
|
||||
PropertyTypeMap() {
|
||||
|
||||
map.put("boolean", new PropertyType("PBoolean"));
|
||||
map.put("short", new PropertyType("PShort"));
|
||||
map.put("int", new PropertyType("PInteger"));
|
||||
@@ -57,7 +56,6 @@ class PropertyTypeMap {
|
||||
addType(Locale.class);
|
||||
addType(File.class);
|
||||
addType(InetAddress.class);
|
||||
|
||||
map.put(URI.class.getName(), new PropertyType("PUri"));
|
||||
map.put(URL.class.getName(), new PropertyType("PUrl"));
|
||||
map.put(UUID.class.getName(), new PropertyType("PUuid"));
|
||||
@@ -74,7 +72,6 @@ class PropertyTypeMap {
|
||||
}
|
||||
|
||||
private void addJava8Types() {
|
||||
|
||||
try {
|
||||
Class.forName("java.time.Instant");
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -94,6 +91,7 @@ class PropertyTypeMap {
|
||||
addType(java.time.YearMonth.class);
|
||||
addType(java.time.ZoneId.class);
|
||||
addType(java.time.ZoneOffset.class);
|
||||
addType(java.time.ZonedDateTime.class);
|
||||
}
|
||||
|
||||
private void addJodaTypes() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>ebean parent</name>
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.8.1</tag>
|
||||
<tag>ebean-parent-12.8.3</tag>
|
||||
</scm>
|
||||
|
||||
<licenses>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.8.1</version>
|
||||
<version>12.8.3</version>
|
||||
</parent>
|
||||
|
||||
<name>querybean generator</name>
|
||||
|
||||
@@ -25,10 +25,9 @@ class PropertyTypeMap {
|
||||
*/
|
||||
private final PropertyType dbJsonType = new PropertyType("PJson");
|
||||
|
||||
private Map<String,PropertyType> map = new HashMap<>();
|
||||
private final Map<String,PropertyType> map = new HashMap<>();
|
||||
|
||||
PropertyTypeMap() {
|
||||
|
||||
map.put("boolean", new PropertyType("PBoolean"));
|
||||
map.put("short", new PropertyType("PShort"));
|
||||
map.put("int", new PropertyType("PInteger"));
|
||||
@@ -57,7 +56,6 @@ class PropertyTypeMap {
|
||||
map.put("java.lang.Class<?>", new PropertyType("PClass"));
|
||||
addType(File.class);
|
||||
addType(InetAddress.class);
|
||||
|
||||
map.put(URI.class.getName(), new PropertyType("PUri"));
|
||||
map.put(URL.class.getName(), new PropertyType("PUrl"));
|
||||
map.put(UUID.class.getName(), new PropertyType("PUuid"));
|
||||
@@ -73,7 +71,6 @@ class PropertyTypeMap {
|
||||
}
|
||||
|
||||
private void addJava8Types() {
|
||||
|
||||
try {
|
||||
Class.forName("java.time.Instant");
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -93,6 +90,7 @@ class PropertyTypeMap {
|
||||
addType(java.time.YearMonth.class);
|
||||
addType(java.time.ZoneId.class);
|
||||
addType(java.time.ZoneOffset.class);
|
||||
addType(java.time.ZonedDateTime.class);
|
||||
}
|
||||
|
||||
private void addJodaTypes() {
|
||||
|
||||
Reference in New Issue
Block a user