mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
214
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
185dec9c02 | ||
|
|
20634233ca | ||
|
|
7c9dda586e | ||
|
|
3ca0f7b776 | ||
|
|
85caca48de | ||
|
|
ff85a51994 | ||
|
|
6dc3038d0d | ||
|
|
c0fcb77f3d | ||
|
|
da5d5296b6 | ||
|
|
f04ab28c3f | ||
|
|
d6cd41f8d2 | ||
|
|
504a209a78 | ||
|
|
9f98b5333d | ||
|
|
2a600adbcf | ||
|
|
9ce6007330 | ||
|
|
7780dd6272 | ||
|
|
b01ddea781 | ||
|
|
b848587cd3 | ||
|
|
fe7e929a99 | ||
|
|
3ee0b0224e | ||
|
|
169eba4296 | ||
|
|
91d3279061 | ||
|
|
b4b7c631da | ||
|
|
4f98ca5d91 | ||
|
|
014a9aef6f | ||
|
|
f21c33df7b | ||
|
|
f1eb494e0d | ||
|
|
d26203db1f | ||
|
|
abfe58fb06 | ||
|
|
d0ad5f6c48 | ||
|
|
bc4a246f33 | ||
|
|
61f590944b | ||
|
|
223e53416d | ||
|
|
a3143b1cf6 | ||
|
|
bd3e7c8035 | ||
|
|
b753ce3a73 | ||
|
|
a0f2ebe448 | ||
|
|
7e7810602e | ||
|
|
d218fff374 | ||
|
|
a0e927d353 | ||
|
|
51a58d4993 | ||
|
|
b9f0ee7ac0 | ||
|
|
4f3b461f8e | ||
|
|
adfe5f0305 | ||
|
|
1796c8b9bc | ||
|
|
4bad4358f0 | ||
|
|
92665ebc3b | ||
|
|
59670d0303 | ||
|
|
244275fd72 | ||
|
|
d1e2176a5a | ||
|
|
43968e70b8 | ||
|
|
0aa3bd3c97 | ||
|
|
2d85a9a20c | ||
|
|
157dfcfeb6 | ||
|
|
2b7c204072 | ||
|
|
be731feb6b | ||
|
|
da15d0b2c6 | ||
|
|
9c5fd496c1 | ||
|
|
5075ea32b4 | ||
|
|
f5c8d8896f | ||
|
|
32fdff9f11 | ||
|
|
87f6964995 | ||
|
|
b45226dd41 | ||
|
|
992c40d362 | ||
|
|
9144d60948 | ||
|
|
6396143d49 | ||
|
|
ce045ca0fe | ||
|
|
d722d34072 | ||
|
|
2cc4c2c265 | ||
|
|
0a830841c4 | ||
|
|
c427009b93 | ||
|
|
7f42d045ac | ||
|
|
43afaf1344 | ||
|
|
6c182ecaa5 | ||
|
|
fdb839f90e | ||
|
|
16be213faf | ||
|
|
3344f0ddb0 | ||
|
|
479ac38537 | ||
|
|
e30ad80f5f | ||
|
|
08e46d6bf3 | ||
|
|
876476fdc1 | ||
|
|
81de83a6e7 | ||
|
|
b5b221ffb1 | ||
|
|
3c6eab6c85 | ||
|
|
1be30f1671 | ||
|
|
9a5cb242ce | ||
|
|
ea69cae4a3 | ||
|
|
629fb7a433 | ||
|
|
4ff10da739 | ||
|
|
9472592a50 | ||
|
|
f42682ca90 | ||
|
|
5dc296e644 | ||
|
|
380660913f | ||
|
|
d08ac6973e | ||
|
|
9d23c1d56e | ||
|
|
b5d6c5f70b | ||
|
|
3657d05774 | ||
|
|
2de8ae777d | ||
|
|
16950a5641 | ||
|
|
ad992d07ce | ||
|
|
cbcec8f5ea | ||
|
|
6e2148d20b | ||
|
|
ca1c0a08f3 | ||
|
|
baa6fc355e | ||
|
|
dacdc26902 | ||
|
|
48edf64013 | ||
|
|
e2ee6e8e98 | ||
|
|
e6e6a28245 | ||
|
|
82a695a98a | ||
|
|
cdad31bd8a | ||
|
|
4d16cf9caa | ||
|
|
84a86cad0e | ||
|
|
dfdf87fa2d | ||
|
|
ee0615caec | ||
|
|
79b8395f8f | ||
|
|
87c479cd95 | ||
|
|
abbdda810a | ||
|
|
e621900de9 | ||
|
|
76b33511e1 | ||
|
|
77deab5cf0 | ||
|
|
4a9f8cef0e | ||
|
|
4d1340c16c | ||
|
|
74c6c71301 | ||
|
|
0f0028eb1f | ||
|
|
b4a1d52067 | ||
|
|
d82148248c | ||
|
|
dc7c854432 | ||
|
|
7c83010df1 | ||
|
|
ed41e58073 | ||
|
|
5bab9eb648 | ||
|
|
5ce8eb6046 | ||
|
|
56fee2ea9b | ||
|
|
84f32c2ace | ||
|
|
85288a0652 | ||
|
|
3183287833 | ||
|
|
780ee7c7c0 | ||
|
|
2bac7bf84d | ||
|
|
499862438d | ||
|
|
4ad0b7cf66 | ||
|
|
6108ef484b | ||
|
|
b763f4c875 | ||
|
|
ca7285b2ad | ||
|
|
75b639bc15 | ||
|
|
1a7c4dac3f | ||
|
|
6828fa1786 | ||
|
|
ba7e729ae1 | ||
|
|
c3fba72a24 | ||
|
|
ff401cfc72 | ||
|
|
7902276296 | ||
|
|
95f7a85aa1 | ||
|
|
cf9eb4ed97 | ||
|
|
b5cb04a6ed | ||
|
|
5a9193f732 | ||
|
|
55584f09d5 | ||
|
|
05eb0bfc55 | ||
|
|
cf13119b49 | ||
|
|
e0eff149b5 | ||
|
|
474c2d5595 | ||
|
|
e58cec8bdd | ||
|
|
9dd82c0dd7 | ||
|
|
49d3cc91e4 | ||
|
|
a8c2fc2ed5 | ||
|
|
45d7e3cafd | ||
|
|
be6754bd06 | ||
|
|
83c16ad1c6 | ||
|
|
3f8b389999 | ||
|
|
b4b6a13e75 | ||
|
|
3fad4aae2f | ||
|
|
ceab95e6c2 | ||
|
|
84b37fb014 | ||
|
|
1a1c432c2a | ||
|
|
86faa947af | ||
|
|
6b54b6ef46 | ||
|
|
d8dfd66af3 | ||
|
|
675c51b8c1 | ||
|
|
3cd7ecaa4a | ||
|
|
1b322955ee | ||
|
|
8115c5e230 | ||
|
|
ad180c5531 | ||
|
|
b454f46dd4 | ||
|
|
8a853b28f3 | ||
|
|
a1be7ba5dd | ||
|
|
3914516793 | ||
|
|
8c5854f77c | ||
|
|
0bc5b94eae | ||
|
|
12fa287f35 | ||
|
|
2991cb9ad1 | ||
|
|
3b7f5496a8 | ||
|
|
4be703ff6e | ||
|
|
d2c5765ac1 | ||
|
|
aaf256b9be | ||
|
|
c7c6410cd9 | ||
|
|
2c3c23725a | ||
|
|
92069c0319 | ||
|
|
630ad66ff1 | ||
|
|
b732b390c7 | ||
|
|
8c62fcdcb2 | ||
|
|
e458f577fe | ||
|
|
23434bab8c | ||
|
|
c47b5a1595 | ||
|
|
411846347b | ||
|
|
3722d19424 | ||
|
|
04a7310e5d | ||
|
|
3490e90f03 | ||
|
|
d89817a5c5 | ||
|
|
db1ba5f20e | ||
|
|
4f9a9a5094 | ||
|
|
1c6ac1289d | ||
|
|
b96be84106 | ||
|
|
3c40293183 | ||
|
|
a9a6031986 | ||
|
|
b82085da42 | ||
|
|
2c34bc1636 | ||
|
|
a954f8e9e1 |
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<version>1.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>7.16.2</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>8.4.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
<name>ebean</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
|
||||
<properties>
|
||||
@@ -36,8 +36,8 @@
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
|
||||
<tag>avaje-ebeanorm-7.16.2</tag>
|
||||
<developerConnection>scm:git:https://github.com/ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-8.4.2</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -69,19 +69,19 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -90,6 +90,12 @@
|
||||
<version>[1.7.1,1.7.99)</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -166,9 +172,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.11.1</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -177,7 +183,7 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.189</version>
|
||||
<version>1.4.192</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -241,16 +247,15 @@
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.11.1</version>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<!--<packages>com.avaje.tests.**</packages>-->
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
@@ -298,7 +303,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 7</doctitle>
|
||||
<doctitle>Ebean 8</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
|
||||
@@ -38,6 +38,11 @@ public interface BeanState {
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Return true if the bean has lazy loading disabled.
|
||||
*/
|
||||
boolean isDisableLazyLoad();
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
*
|
||||
@@ -115,4 +120,9 @@ public interface BeanState {
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
|
||||
/**
|
||||
* Reset the bean putting it into NEW state such that a save() results in an insert.
|
||||
*/
|
||||
void resetForInsert();
|
||||
}
|
||||
@@ -499,6 +499,13 @@ public final class Ebean {
|
||||
serverMgr.getDefaultServer().endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current transaction as rollback only.
|
||||
*/
|
||||
public static void setRollbackOnly() {
|
||||
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
* <p>
|
||||
@@ -945,6 +952,21 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createCsvReader(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named query.
|
||||
* <p>
|
||||
* For RawSql the named query is expected to be in ebean.xml.
|
||||
* </p>
|
||||
*
|
||||
* @param beanType The type of entity bean
|
||||
* @param namedQuery The name of the query
|
||||
* @param <T> The type of entity bean
|
||||
* @return The query
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -960,39 +982,7 @@ public final class Ebean {
|
||||
* {@link Query#findSet()} etc will execute against the same EbeanServer from
|
||||
* which is was created.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
*
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.find(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
* @return A ORM Query object for this beanType
|
||||
@@ -1002,6 +992,47 @@ public final class Ebean {
|
||||
return serverMgr.getDefaultServer().createQuery(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Ebean query language statement returning the query which can then
|
||||
* be modified (add expressions, change order by clause, change maxRows, change
|
||||
* fetch and select paths etc).
|
||||
*
|
||||
* <h3>Example</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* // Find order additionally fetching the customer, details and details.product name.
|
||||
*
|
||||
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of bean to fetch
|
||||
* @param eql The Ebean query
|
||||
* @param <T> The type of the entity bean
|
||||
*
|
||||
* @return The query with expressions defined as per the parsed query statement
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
|
||||
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, eql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
|
||||
@@ -167,8 +167,9 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Create a new instance of T that is an EntityBean.
|
||||
* <p>
|
||||
* Generally not expected to be useful (now dynamic subclassing support was removed in
|
||||
* favour of always using enhancement).
|
||||
* Useful if you use BeanPostConstructListeners or @PostConstruct Annotations.
|
||||
* In this case you should not use "new Bean...()". Making all bean construtors protected
|
||||
* could be a good idea here.
|
||||
* </p>
|
||||
*/
|
||||
<T> T createEntityBean(Class<T> type);
|
||||
@@ -199,6 +200,19 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> UpdateQuery<T> update(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Create a named query.
|
||||
* <p>
|
||||
* For RawSql the named query is expected to be in ebean.xml.
|
||||
* </p>
|
||||
*
|
||||
* @param beanType The type of entity bean
|
||||
* @param namedQuery The name of the query
|
||||
* @param <T> The type of entity bean
|
||||
* @return The query
|
||||
*/
|
||||
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
|
||||
|
||||
/**
|
||||
* Create a query for an entity bean and synonym for {@link #find(Class)}.
|
||||
*
|
||||
@@ -206,6 +220,43 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> Query<T> createQuery(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Parse the Ebean query language statement returning the query which can then
|
||||
* be modified (add expressions, change order by clause, change maxRows, change
|
||||
* fetch and select paths etc).
|
||||
*
|
||||
* <h3>Example</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Find order additionally fetching the customer, details and details.product name.
|
||||
*
|
||||
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, eql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* // This is the same as:
|
||||
*
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType The type of bean to fetch
|
||||
* @param eql The Ebean query
|
||||
* @param <T> The type of the entity bean
|
||||
*
|
||||
* @return The query with expressions defined as per the parsed query statement
|
||||
*/
|
||||
<T> Query<T> createQuery(Class<T> beanType, String eql);
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
* <p>
|
||||
@@ -689,20 +740,38 @@ public interface EbeanServer {
|
||||
<T> T getReference(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should
|
||||
* return.
|
||||
* Return the number of 'top level' or 'root' entities this query should return.
|
||||
*
|
||||
* @see Query#findRowCount()
|
||||
* @see com.avaje.ebean.Query#findFutureRowCount()
|
||||
* @see Query#findCount()
|
||||
* @see Query#findFutureCount()
|
||||
*/
|
||||
<T> int findRowCount(Query<T> query, Transaction transaction);
|
||||
<T> int findCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return the Id values of the query as a List.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#findIds()
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
<T> List<Object> findIds(Query<T> query, Transaction transaction);
|
||||
<A> List<A> findIds(Query<?> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a QueryIterator for the query.
|
||||
* <p>
|
||||
* Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or
|
||||
* {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred
|
||||
* to findIterate(). The reason is that those methods automatically take care of
|
||||
* closing the queryIterator (and the underlying jdbc statement and resultSet).
|
||||
* </p>
|
||||
* <p>
|
||||
* This is similar to findEach in that not all the result beans need to be held
|
||||
* in memory at the same time and as such is good for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
@@ -816,9 +885,9 @@ public interface EbeanServer {
|
||||
* @param query the query to execute the row count on
|
||||
* @param transaction the transaction (can be null).
|
||||
* @return a Future object for the row count query
|
||||
* @see com.avaje.ebean.Query#findFutureRowCount()
|
||||
* @see com.avaje.ebean.Query#findFutureCount()
|
||||
*/
|
||||
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
|
||||
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -921,7 +990,41 @@ public interface EbeanServer {
|
||||
* @return the map of fetched beans.
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
|
||||
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning a list of values for a single property.
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
*
|
||||
* @see Query#findSingleAttributeList()
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList(Query<?> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning at most one entity bean or null (if no matching
|
||||
|
||||
@@ -135,6 +135,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To that allows for named parameter use.
|
||||
*/
|
||||
Expression ieqObject(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
@@ -192,6 +197,11 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like with support for named parameters.
|
||||
*/
|
||||
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.Set;
|
||||
* more methods than you would initially expect (the ones duplicated from
|
||||
* Query).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionList<T> {
|
||||
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> orderBy(String orderBy);
|
||||
|
||||
/**
|
||||
* Add an orderBy clause to the query.
|
||||
*
|
||||
*
|
||||
* @see Query#orderBy(String)
|
||||
*/
|
||||
Query<T> setOrderBy(String orderBy);
|
||||
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> asDraft();
|
||||
|
||||
/**
|
||||
* Deprecated in favour of setIncludeSoftDeletes().
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> includeSoftDeletes();
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
@@ -147,6 +141,13 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
int update();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
* @see Query#findIterate()
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query process the beans one at a time.
|
||||
*
|
||||
@@ -164,17 +165,17 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*
|
||||
*
|
||||
* @see Query#findList()
|
||||
*/
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
*
|
||||
*
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
@@ -182,26 +183,53 @@ public interface ExpressionList<T> {
|
||||
* This is the number of 'top level' or 'root level' entities.
|
||||
* </p>
|
||||
*/
|
||||
int findRowCount();
|
||||
int findCount();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
*
|
||||
*
|
||||
* @see Query#findSet()
|
||||
*/
|
||||
Set<T> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
*
|
||||
*
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
Map<?, T> findMap();
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Return a typed map specifying the key property and type.
|
||||
* Execute the query returning a list of values for a single property.
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
*/
|
||||
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single bean or null (if no matching
|
||||
@@ -225,10 +253,10 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the row count query
|
||||
*/
|
||||
FutureRowCount<T> findFutureRowCount();
|
||||
FutureRowCount<T> findFutureCount();
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -237,7 +265,7 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list of Id's
|
||||
*/
|
||||
FutureIds<T> findFutureIds();
|
||||
@@ -249,7 +277,7 @@ public interface ExpressionList<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
*/
|
||||
FutureList<T> findFutureList();
|
||||
@@ -312,7 +340,7 @@ public interface ExpressionList<T> {
|
||||
/**
|
||||
* Specify specific properties to fetch on the main/root bean (aka partial
|
||||
* object).
|
||||
*
|
||||
*
|
||||
* @see Query#select(String)
|
||||
*/
|
||||
Query<T> select(String properties);
|
||||
@@ -337,28 +365,28 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setFirstRow(int)
|
||||
*/
|
||||
Query<T> setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of rows to fetch.
|
||||
*
|
||||
*
|
||||
* @see Query#setMaxRows(int)
|
||||
*/
|
||||
Query<T> setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the name of the property which values become the key of a map.
|
||||
*
|
||||
*
|
||||
* @see Query#setMapKey(String)
|
||||
*/
|
||||
Query<T> setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set to true to use the query for executing this query.
|
||||
*
|
||||
*
|
||||
* @see Query#setUseCache(boolean)
|
||||
*/
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
@@ -619,7 +647,7 @@ public interface ExpressionList<T> {
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create an example bean and set the properties
|
||||
@@ -627,26 +655,26 @@ public interface ExpressionList<T> {
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -748,7 +776,7 @@ public interface ExpressionList<T> {
|
||||
* Exists expression
|
||||
*/
|
||||
ExpressionList<T> exists(Query<?> subQuery);
|
||||
|
||||
|
||||
/**
|
||||
* Not exists expression
|
||||
*/
|
||||
@@ -775,7 +803,7 @@ public interface ExpressionList<T> {
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
|
||||
@@ -29,8 +29,7 @@ import java.io.Serializable;
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
@@ -117,7 +116,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
@@ -125,12 +124,7 @@ import java.io.Serializable;
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
List<Object> getPartialIds();
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ package com.avaje.ebean;
|
||||
* .and()
|
||||
* .startsWith("name", "r")
|
||||
* .eq("anniversary", onAfter)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .and()
|
||||
* .eq("status", Customer.Status.ACTIVE)
|
||||
* .gt("id", 0)
|
||||
* .endJunction()
|
||||
* .endAnd()
|
||||
* .order().asc("name");
|
||||
*
|
||||
* q.findList();
|
||||
@@ -84,39 +84,41 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
/**
|
||||
* AND group.
|
||||
*/
|
||||
AND(" and ", ""),
|
||||
AND(" and ", "", false),
|
||||
|
||||
/**
|
||||
* OR group.
|
||||
*/
|
||||
OR(" or ", ""),
|
||||
OR(" or ", "", false),
|
||||
|
||||
/**
|
||||
* NOT group.
|
||||
*/
|
||||
NOT(" and ", "not "),
|
||||
NOT(" and ", "not ", false),
|
||||
|
||||
/**
|
||||
* Text search AND group.
|
||||
*/
|
||||
MUST("must", ""),
|
||||
MUST("must", "", true),
|
||||
|
||||
/**
|
||||
* Text search NOT group.
|
||||
*/
|
||||
MUST_NOT("must_not", ""),
|
||||
MUST_NOT("must_not", "", true),
|
||||
|
||||
/**
|
||||
* Text search OR group.
|
||||
*/
|
||||
SHOULD("should", "");
|
||||
SHOULD("should", "", true);
|
||||
|
||||
String prefix;
|
||||
String literal;
|
||||
private String prefix;
|
||||
private String literal;
|
||||
private boolean text;
|
||||
|
||||
Type(String literal, String prefix) {
|
||||
Type(String literal, String prefix, boolean text) {
|
||||
this.literal = literal;
|
||||
this.prefix = prefix;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,6 +134,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
|
||||
public String prefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a text type.
|
||||
*/
|
||||
public boolean isText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ public abstract class Model {
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivilent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
@@ -598,7 +598,7 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public List<Object> findIds() {
|
||||
public <A> List<A> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
@@ -660,36 +660,43 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query().findMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns the results as a map of the objects specifying the map key
|
||||
* property.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap(String, Class)}
|
||||
*/
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return query().findMap(keyProperty, keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureRowCount()}
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findFutureCount().
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query().findFutureRowCount();
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findRowCount()}
|
||||
* Equivalent to {@link Query#findCount()}
|
||||
*/
|
||||
public int findCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findCount().
|
||||
* @deprecated
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findRowCount();
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -148,6 +148,13 @@ public final class OrderBy<T> implements Serializable {
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the order by by parsing a raw expression.
|
||||
*/
|
||||
public void add(String rawExpression) {
|
||||
parse(rawExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
@@ -206,8 +213,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
* order by clause and replace.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
public OrderBy<T> clear() {
|
||||
list.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,30 +44,6 @@ import java.util.concurrent.Future;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 100 new orders
|
||||
* // ... 0 means first page
|
||||
* // ... page size is 100
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findPagedList(0, 100);
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
@@ -110,7 +86,7 @@ public interface PagedList<T> {
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
void loadRowCount();
|
||||
void loadCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
@@ -138,7 +114,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Future<Integer> getFutureRowCount();
|
||||
Future<Integer> getFutureCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
@@ -170,7 +146,7 @@ public interface PagedList<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
int getTotalRowCount();
|
||||
int getTotalCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
@@ -186,6 +162,14 @@ public interface PagedList<T> {
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Return the index position of this page (Zero based).
|
||||
* <p>
|
||||
* This is a calculated value based on firstRow/maxRows.
|
||||
* </p>
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
|
||||
@@ -13,10 +13,10 @@ import java.util.Set;
|
||||
* <p>
|
||||
* Example: Create the query using the API.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orderList =
|
||||
* List<Order> orderList =
|
||||
* ebeanServer.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
@@ -26,46 +26,40 @@ import java.util.Set;
|
||||
* .orderBy("customer.id, id desc")
|
||||
* .setMaxRows(50)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example: The same query using the query language
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String oql =
|
||||
* " find order "
|
||||
* String oql =
|
||||
* +" fetch customer "
|
||||
* +" fetch details "
|
||||
* +" where customer.name like :custName and orderDate > :minOrderDate "
|
||||
* +" order by customer.id, id desc "
|
||||
* +" limit 50 ";
|
||||
*
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example: Using a named query called "with.cust.and.details"
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>AutoTune</h3>
|
||||
* <p>
|
||||
* Ebean has built in support for "AutoTune". This is a mechanism where a query
|
||||
@@ -82,7 +76,6 @@ import java.util.Set;
|
||||
* to a remote client or where there is some requirement for "Read Consistency"
|
||||
* guarantees.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Query Language</h3>
|
||||
* <p>
|
||||
* <b>Partial Objects</b>
|
||||
@@ -101,36 +94,25 @@ import java.util.Set;
|
||||
* concurrency checking will occur but only include the fetched properties.
|
||||
* Refer to "ALL Properties/Columns" mode of Optimistic Concurrency checking.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* [ find {bean type} [ ( * | {fetch properties} ) ] ]
|
||||
* [ fetch {associated bean} [ ( * | {fetch properties} ) ] ]
|
||||
* [ select [ ( * | {fetch properties} ) ] ]
|
||||
* [ fetch {path} [ ( * | {fetch properties} ) ] ]
|
||||
* [ where {predicates} ]
|
||||
* [ order by {order by properties} ]
|
||||
* [ limit {max rows} [ offset {first row} ] ]
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>FIND</b> <b>{bean type}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
|
||||
* <b>SELECT</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
|
||||
* </p>
|
||||
* <p>
|
||||
* With the find you specify the type of beans to fetch. You can optionally
|
||||
* specify a list of properties to fetch. If you do not specify a list of
|
||||
* properties ALL the properties for those beans are fetched.
|
||||
* With the select you can specify a list of properties to fetch.
|
||||
* </p>
|
||||
* <p>
|
||||
* In object graph terms the <em>find</em> clause specifies the type of bean at
|
||||
* the root level and the <em>fetch</em> clauses specify the paths of the object
|
||||
* graph to populate.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>FETCH</b> <b>{associated property}</b> [ ( <i>*</i> | <i>{fetch
|
||||
* properties}</i> ) ]
|
||||
* <b>FETCH</b> <b>{path}</b> [ ( <i>*</i> | <i>{fetch properties}</i> ) ]
|
||||
* </p>
|
||||
* <p>
|
||||
* With the fetch you specify the associated property to fetch and populate. The
|
||||
* associated property is a OneToOnem, ManyToOne, OneToMany or ManyToMany
|
||||
* property. When the query is executed Ebean will fetch the associated data.
|
||||
* path is a OneToOne, ManyToOne, OneToMany or ManyToMany property.
|
||||
* </p>
|
||||
* <p>
|
||||
* For fetch of a path we can optionally specify a list of properties to fetch.
|
||||
@@ -161,52 +143,34 @@ import java.util.Set;
|
||||
* </p>
|
||||
* <h4>Examples of Ebean's Query Language</h4>
|
||||
* <p>
|
||||
* Find orders fetching all its properties
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Find orders fetching all its properties
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order (*)
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Find orders fetching its id, shipDate and status properties. Note that the id
|
||||
* property is always fetched even if it is not included in the list of fetch
|
||||
* properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order (shipDate, status)
|
||||
*
|
||||
* select (shipDate, status)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Find orders with a named bind variable (that will need to be bound via
|
||||
* {@link Query#setParameter(String, Object)}).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order
|
||||
*
|
||||
* where customer.name like :custLike
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Find orders and also fetch the customer with a named bind parameter. This
|
||||
* will fetch and populate both the order and customer objects.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order
|
||||
*
|
||||
* fetch customer
|
||||
* where customer.id = :custId
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Find orders and also fetch the customer, customer shippingAddress, order
|
||||
* details and related product. Note that customer and product objects will be
|
||||
@@ -215,63 +179,16 @@ import java.util.Set;
|
||||
* objects (associated with each order detail) will have their id, sku and name
|
||||
* populated.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* find order
|
||||
*
|
||||
* fetch customer (name)
|
||||
* fetch customer.shippingAddress
|
||||
* fetch details
|
||||
* fetch details.product (sku, name)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Early parsing of the Query</h3>
|
||||
* <p>
|
||||
* When you get a Query object from a named query, the query statement has
|
||||
* already been parsed. You can then add to that query (add fetch paths, add to
|
||||
* the where clause) or override some of its settings (override the order by
|
||||
* clause, first rows, max rows).
|
||||
* </p>
|
||||
* <p>
|
||||
* The thought is that you can use named queries as a 'starting point' and then
|
||||
* modify the query to suit specific needs.
|
||||
* </p>
|
||||
* <h3>Building the Where clause</h3>
|
||||
* <p>
|
||||
* You can add to the where clause using Expression objects or a simple String.
|
||||
* Note that the ExpressionList has methods to add most of the common
|
||||
* expressions that you will need.
|
||||
* <ul>
|
||||
* <li>where(String addToWhereClause)</li>
|
||||
* <li>where().add(Expression expression)</li>
|
||||
* <li>where().eq(propertyName, value).like(propertyName , value)...</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* The full WHERE clause is constructed by appending together
|
||||
* <li>original query where clause (Named query or query.setQuery(String oql))</li>
|
||||
* <li>clauses added via query.where(String addToWhereClause)</li>
|
||||
* <li>clauses added by Expression objects</li>
|
||||
* </p>
|
||||
* <p>
|
||||
* The above is the order that these are clauses are appended to give the full
|
||||
* WHERE clause.
|
||||
* </p>
|
||||
* <h3>Design Goal</h3>
|
||||
* <p>
|
||||
* This query language is NOT designed to be a replacement for SQL. It is
|
||||
* designed to be a simple way to describe the "Object Graph" you want Ebean to
|
||||
* build for you. Each find/fetch represents a node in that "Object Graph" which
|
||||
* makes it easy to define for each node which properties you want to fetch.
|
||||
* </p>
|
||||
* <p>
|
||||
* Once you hit the limits of this language such as wanting aggregate functions
|
||||
* (sum, average, min etc) or recursive queries etc you use SQL. Ebean's goal is
|
||||
* to make it as easy as possible to use your own SQL to populate entity beans.
|
||||
* Refer to {@link RawSql} .
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of Entity bean this query will fetch.
|
||||
*
|
||||
* @param <T> the type of Entity bean this query will fetch.
|
||||
*/
|
||||
public interface Query<T> {
|
||||
|
||||
@@ -289,7 +206,7 @@ public interface Query<T> {
|
||||
* Perform an 'As of' query using history tables to return the object graph
|
||||
* as of a time in the past.
|
||||
* <p>
|
||||
* To perform this query the DB must have underlying history tables.
|
||||
* To perform this query the DB must have underlying history tables.
|
||||
* </p>
|
||||
*
|
||||
* @param asOf the date time in the past at which you want to view the data
|
||||
@@ -325,7 +242,7 @@ public interface Query<T> {
|
||||
* Specify the PersistenceContextScope to use for this query.
|
||||
* <p/>
|
||||
* When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}.
|
||||
* is used - this value defaults to {@link PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
|
||||
* <p/>
|
||||
@@ -392,14 +309,15 @@ public interface Query<T> {
|
||||
Query<T> setDisableReadAuditing();
|
||||
|
||||
/**
|
||||
* Explicitly set a comma delimited list of the properties to fetch on the
|
||||
* 'main' root level entity bean (aka partial object). Note that '*' means all
|
||||
* properties.
|
||||
* Specify the properties to fetch on the root level entity bean in comma delimited format.
|
||||
* <p>
|
||||
* You use {@link #fetch(String, String)} to specify specific properties to fetch
|
||||
* The Id property is automatically included in the properties to fetch unless setDistinct(true)
|
||||
* is set on the query.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use {@link #fetch(String, String)} to specify specific properties to fetch
|
||||
* on other non-root level paths of the object graph.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
@@ -412,42 +330,33 @@ public interface Query<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param fetchProperties
|
||||
* the properties to fetch for this bean (* = all properties).
|
||||
* @param fetchProperties the properties to fetch for this bean (* = all properties).
|
||||
*/
|
||||
Query<T> select(String fetchProperties);
|
||||
|
||||
/**
|
||||
* Specify a path to <em>fetch</em> with its specific properties to include
|
||||
* (aka partial object).
|
||||
* Specify a path to fetch eagerly including specific properties.
|
||||
* <p>
|
||||
* When you specify a join this means that property (associated bean(s)) will
|
||||
* be fetched and populated. If you specify "*" then all the properties of the
|
||||
* associated bean will be fetched and populated. You can specify a comma
|
||||
* delimited list of the properties of that associated bean which means that
|
||||
* only those properties are fetched and populated resulting in a
|
||||
* "Partial Object" - a bean that only has some of its properties populated.
|
||||
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
|
||||
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
|
||||
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // query orders...
|
||||
* List<Order> orders =
|
||||
* ebeanserver.find(Order.class)
|
||||
* ebeanServer.find(Order.class)
|
||||
* // fetch the customer...
|
||||
* // ... getting the customers name and phone number
|
||||
* .fetch("customer", "name, phoneNumber")
|
||||
*
|
||||
*
|
||||
* // ... also fetch the customers billing address (* = all properties)
|
||||
* .fetch("customer.billingAddress", "*")
|
||||
* .findList();
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* If columns is null or "*" then all columns/properties for that path are
|
||||
* fetched.
|
||||
* If columns is null or "*" then all columns/properties for that path are fetched.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
@@ -458,19 +367,66 @@ public interface Query<T> {
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param path
|
||||
* the path of an associated (1-1,1-M,M-1,M-M) bean.
|
||||
* @param fetchProperties
|
||||
* properties of the associated bean that you want to include in the
|
||||
* fetch (* means all properties, null also means all properties).
|
||||
*
|
||||
* @param path the property path we wish to fetch eagerly.
|
||||
* @param fetchProperties properties of the associated bean that you want to include in the
|
||||
* fetch (* means all properties, null also means all properties).
|
||||
*/
|
||||
Query<T> fetch(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties using a "query join" (separate SQL query).
|
||||
* <p>
|
||||
* This is the same as:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().query())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
|
||||
* part of the object graph rather than a SQL join.
|
||||
* </p>
|
||||
* <p>
|
||||
* We might typically get a performance benefit when the path to fetch is a OneToMany
|
||||
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
|
||||
* is high.
|
||||
* </p>
|
||||
*
|
||||
* @param path the property path we wish to fetch eagerly.
|
||||
* @param fetchProperties properties of the associated bean that you want to include in the
|
||||
* fetch (* means all properties, null also means all properties).
|
||||
*/
|
||||
Query<T> fetchQuery(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Fetch the path and properties lazily (via batch lazy loading).
|
||||
* <p>
|
||||
* This is the same as:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().lazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* The reason for using fetchLazy() is to either:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Control/tune what is fetched as part of lazy loading</li>
|
||||
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param path the property path we wish to fetch lazily.
|
||||
* @param fetchProperties properties of the associated bean that you want to include in the
|
||||
* fetch (* means all properties, null also means all properties).
|
||||
*/
|
||||
Query<T> fetchLazy(String path, String fetchProperties);
|
||||
|
||||
/**
|
||||
* Additionally specify a FetchConfig to use a separate query or lazy loading
|
||||
* to load this path.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
@@ -481,13 +437,17 @@ public interface Query<T> {
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param path the property path we wish to fetch eagerly.
|
||||
*/
|
||||
Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig);
|
||||
Query<T> fetch(String path, String fetchProperties, FetchConfig fetchConfig);
|
||||
|
||||
/**
|
||||
* Specify a path to load including all its properties.
|
||||
* Specify a path to fetch eagerly including all its properties.
|
||||
* <p>
|
||||
* The same as {@link #fetch(String, String)} with the fetchProperties as "*".
|
||||
* Ebean will endeavour to fetch this path using a SQL join. If Ebean determines that it can
|
||||
* not use a SQL join (due to maxRows or because it would result in a cartesian product) Ebean
|
||||
* will automatically convert this fetch query into a "query join" - i.e. use fetchQuery().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -500,16 +460,59 @@ public interface Query<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param path
|
||||
* the property of an associated (1-1,1-M,M-1,M-M) bean.
|
||||
* @param path the property path we wish to fetch eagerly.
|
||||
*/
|
||||
Query<T> fetch(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path eagerly using a "query join" (separate SQL query).
|
||||
* <p>
|
||||
* This is the same as:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().query())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This would be used instead of a fetch() when we use a separate SQL query to fetch this
|
||||
* part of the object graph rather than a SQL join.
|
||||
* </p>
|
||||
* <p>
|
||||
* We might typically get a performance benefit when the path to fetch is a OneToMany
|
||||
* or ManyToMany, the 'width' of the 'root bean' is wide and the cardinality of the many
|
||||
* is high.
|
||||
* </p>
|
||||
*
|
||||
* @param path the property path we wish to fetch eagerly
|
||||
*/
|
||||
Query<T> fetchQuery(String path);
|
||||
|
||||
/**
|
||||
* Fetch the path lazily (via batch lazy loading).
|
||||
* <p>
|
||||
* This is the same as:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().lazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* The reason for using fetchLazy() is to either:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Control/tune what is fetched as part of lazy loading</li>
|
||||
* <li>Make use of the L2 cache, build this part of the graph from L2 cache</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param path the property path we wish to fetch lazily.
|
||||
*/
|
||||
Query<T> fetchLazy(String path);
|
||||
|
||||
/**
|
||||
* Additionally specify a JoinConfig to specify a "query join" and or define
|
||||
* the lazy loading query.
|
||||
*
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
@@ -536,10 +539,50 @@ public interface Query<T> {
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see EbeanServer#findIds(Query, Transaction)
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
* <p>
|
||||
* findEach() and findEachWhile() are preferred to findIterate() as they ensure
|
||||
* the jdbc statement and resultSet are closed at the end of the iteration.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
@@ -549,6 +592,11 @@ public interface Query<T> {
|
||||
* (unlike #findList #findSet etc)
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findEach (and findEachWhile and findIterate) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that internally Ebean can inform the JDBC driver that it is expecting larger
|
||||
* resultSet and specifically for MySQL this hint is required to stop it's JDBC driver
|
||||
* from buffering the entire resultSet. As such, for smaller resultSets findList() is
|
||||
@@ -564,7 +612,6 @@ public interface Query<T> {
|
||||
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
@@ -578,8 +625,7 @@ public interface Query<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
* @param consumer the consumer used to process the queried beans.
|
||||
*/
|
||||
void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
@@ -587,12 +633,15 @@ public interface Query<T> {
|
||||
* Execute the query using callbacks to a visitor to process the resulting
|
||||
* beans one at a time.
|
||||
* <p>
|
||||
* Note that findEachWhile (and findEach and findIterate) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
@@ -611,8 +660,7 @@ public interface Query<T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
* @param consumer the consumer used to process the queried beans.
|
||||
*/
|
||||
void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
@@ -621,7 +669,6 @@ public interface Query<T> {
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
@@ -640,7 +687,6 @@ public interface Query<T> {
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
@@ -663,24 +709,50 @@ public interface Query<T> {
|
||||
* You can use setMapKey() so specify the property values to be used as keys
|
||||
* on the map. If one is not specified then the id property is used.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Map<?, Product> map =
|
||||
* Map<String, Product> map =
|
||||
* ebeanServer.find(Product.class)
|
||||
* .setMapKey("sku")
|
||||
* .findMap();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @see EbeanServer#findMap(Query, Transaction)
|
||||
*/
|
||||
Map<?, T> findMap();
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Return a typed map specifying the key property and type.
|
||||
* Execute the query returning a list of values for a single property.
|
||||
*
|
||||
* <h3>Example 1:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example 2:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
* .orderBy().asc("name")
|
||||
* .setMaxRows(100)
|
||||
* .findSingleAttributeList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @return the list of values for the selected property
|
||||
*/
|
||||
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Execute the query returning either a single bean or null (if no matching
|
||||
@@ -693,7 +765,6 @@ public interface Query<T> {
|
||||
* This is useful when your predicates dictate that your query should only
|
||||
* return 0 or 1 results.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assuming the sku of products is unique...
|
||||
@@ -703,16 +774,14 @@ public interface Query<T> {
|
||||
* .findUnique();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* It is also useful with finding objects by their id when you want to specify
|
||||
* further join information.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Fetch order 1 and additionally fetch join its order details...
|
||||
* Order order =
|
||||
* Order order =
|
||||
* ebeanServer.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
@@ -731,13 +800,13 @@ public interface Query<T> {
|
||||
/**
|
||||
* Return versions of a @History entity bean.
|
||||
* <p>
|
||||
* Note that this query will work against view based history implementations
|
||||
* but not sql2011 standards based implementations that require a start and
|
||||
* end timestamp to be specified.
|
||||
* Note that this query will work against view based history implementations
|
||||
* but not sql2011 standards based implementations that require a start and
|
||||
* end timestamp to be specified.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* </p>
|
||||
*/
|
||||
List<Version<T>> findVersions();
|
||||
@@ -745,8 +814,8 @@ public interface Query<T> {
|
||||
/**
|
||||
* Return versions of a @History entity bean between the 2 timestamps.
|
||||
* <p>
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* </p>
|
||||
*/
|
||||
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
|
||||
@@ -774,7 +843,7 @@ public interface Query<T> {
|
||||
* This is the number of 'top level' or 'root level' entities.
|
||||
* </p>
|
||||
*/
|
||||
int findRowCount();
|
||||
int findCount();
|
||||
|
||||
/**
|
||||
* Execute find row count query in a background thread.
|
||||
@@ -783,10 +852,10 @@ public interface Query<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the row count query
|
||||
*/
|
||||
FutureRowCount<T> findFutureRowCount();
|
||||
FutureRowCount<T> findFutureCount();
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -795,7 +864,7 @@ public interface Query<T> {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list of Id's
|
||||
*/
|
||||
FutureIds<T> findFutureIds();
|
||||
@@ -821,7 +890,6 @@ public interface Query<T> {
|
||||
* If maxRows is not set on the query prior to calling findPagedList() then a
|
||||
* PersistenceException is thrown.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
@@ -843,24 +911,21 @@ public interface Query<T> {
|
||||
|
||||
/**
|
||||
* Set a named bind parameter. Named parameters have a colon to prefix the name.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // a query with a named parameter
|
||||
* String oql = "find order where status = :orderStatus";
|
||||
*
|
||||
*
|
||||
* Query<Order> query = ebeanServer.find(Order.class, oql);
|
||||
*
|
||||
*
|
||||
* // bind the named parameter
|
||||
* query.bind("orderStatus", OrderStatus.NEW);
|
||||
* List<Order> list = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param name
|
||||
* the parameter name
|
||||
* @param value
|
||||
* the parameter value
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @param value the parameter value
|
||||
*/
|
||||
Query<T> setParameter(String name, Object value);
|
||||
|
||||
@@ -868,25 +933,22 @@ public interface Query<T> {
|
||||
* Set an ordered bind parameter according to its position. Note that the
|
||||
* position starts at 1 to be consistent with JDBC PreparedStatement. You need
|
||||
* to set a parameter value for each ? you have in the query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // a query with a positioned parameter
|
||||
* String oql = "where status = ? order by id desc";
|
||||
*
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
*
|
||||
*
|
||||
* // bind the parameter
|
||||
* query.setParameter(1, OrderStatus.NEW);
|
||||
*
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param position
|
||||
* the parameter bind position starting from 1 (not 0)
|
||||
* @param value
|
||||
* the parameter bind value.
|
||||
*
|
||||
* @param position the parameter bind position starting from 1 (not 0)
|
||||
* @param value the parameter bind value.
|
||||
*/
|
||||
Query<T> setParameter(int position, Object value);
|
||||
|
||||
@@ -896,7 +958,6 @@ public interface Query<T> {
|
||||
* You can use this to have further control over the query. For example adding
|
||||
* fetch joins.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Order order =
|
||||
@@ -919,10 +980,9 @@ public interface Query<T> {
|
||||
|
||||
/**
|
||||
* Add a single Expression to the where clause returning the query.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> newOrders =
|
||||
* List<Order> newOrders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.NEW)
|
||||
* .findList();
|
||||
@@ -936,7 +996,6 @@ public interface Query<T> {
|
||||
* Add Expressions to the where clause with the ability to chain on the
|
||||
* ExpressionList. You can use this for adding multiple expressions to the
|
||||
* where clause.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orders =
|
||||
@@ -947,9 +1006,9 @@ public interface Query<T> {
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see Expr
|
||||
*
|
||||
* @return The ExpressionList for adding expressions to.
|
||||
* @see Expr
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
@@ -984,9 +1043,8 @@ public interface Query<T> {
|
||||
* each customer you only want to get the new orders they placed since last
|
||||
* week. In this case you can use filterMany() to filter the orders.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* List<Customer> list =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* // .fetch("orders", new FetchConfig().lazy())
|
||||
@@ -995,20 +1053,17 @@ public interface Query<T> {
|
||||
* .where().ilike("name", "rob%")
|
||||
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
|
||||
* .findList();
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Please note you have to be careful that you add expressions to the correct
|
||||
* expression list - as there is one for the 'root level' and one for each
|
||||
* filterMany that you have.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyName
|
||||
* the name of the many property that you want to have a filter on.
|
||||
*
|
||||
*
|
||||
* @param propertyName the name of the many property that you want to have a filter on.
|
||||
* @return the expression list that you add filter expressions for the many
|
||||
* to.
|
||||
* to.
|
||||
*/
|
||||
ExpressionList<T> filterMany(String propertyName);
|
||||
|
||||
@@ -1021,9 +1076,9 @@ public interface Query<T> {
|
||||
* Note that this returns the ExpressionList (so you can add multiple
|
||||
* expressions to the query in a fluent API way).
|
||||
* </p>
|
||||
*
|
||||
* @see Expr
|
||||
*
|
||||
* @return The ExpressionList for adding more expressions to.
|
||||
* @see Expr
|
||||
*/
|
||||
ExpressionList<T> having();
|
||||
|
||||
@@ -1037,9 +1092,8 @@ public interface Query<T> {
|
||||
* than the ExpressionList. This is useful when you want to further specify
|
||||
* something on the query.
|
||||
* </p>
|
||||
*
|
||||
* @param addExpressionToHaving
|
||||
* the expression to add to the having clause.
|
||||
*
|
||||
* @param addExpressionToHaving the expression to add to the having clause.
|
||||
* @return the Query object
|
||||
*/
|
||||
Query<T> having(Expression addExpressionToHaving);
|
||||
@@ -1151,9 +1205,8 @@ public interface Query<T> {
|
||||
|
||||
/**
|
||||
* Set the maximum number of rows to return in the query.
|
||||
*
|
||||
* @param maxRows
|
||||
* the maximum number of rows to return in the query.
|
||||
*
|
||||
* @param maxRows the maximum number of rows to return in the query.
|
||||
*/
|
||||
Query<T> setMaxRows(int maxRows);
|
||||
|
||||
@@ -1162,11 +1215,10 @@ public interface Query<T> {
|
||||
* <p>
|
||||
* If no property is set then the id property is used.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Assuming sku is unique for products...
|
||||
*
|
||||
*
|
||||
* Map<?,Product> productMap =
|
||||
* ebeanServer.find(Product.class)
|
||||
* // use sku for keys...
|
||||
@@ -1174,9 +1226,8 @@ public interface Query<T> {
|
||||
* .findMap();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param mapKey
|
||||
* the property to use as keys for a map.
|
||||
*
|
||||
* @param mapKey the property to use as keys for a map.
|
||||
*/
|
||||
Query<T> setMapKey(String mapKey);
|
||||
|
||||
@@ -1203,7 +1254,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Set to true if this query should execute against the doc store.
|
||||
* <p>
|
||||
* When setting this you may also consider disabling lazy loading.
|
||||
* When setting this you may also consider disabling lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setUseDocStore(boolean useDocStore);
|
||||
@@ -1226,9 +1277,8 @@ public interface Query<T> {
|
||||
* preparedStatement. If the timeout occurs an exception will be thrown - this
|
||||
* will be a SQLException wrapped up in a PersistenceException.
|
||||
* </p>
|
||||
*
|
||||
* @param secs
|
||||
* the query timeout limit in seconds. Zero means there is no limit.
|
||||
*
|
||||
* @param secs the query timeout limit in seconds. Zero means there is no limit.
|
||||
*/
|
||||
Query<T> setTimeout(int secs);
|
||||
|
||||
@@ -1238,6 +1288,16 @@ public interface Query<T> {
|
||||
* Gives the JDBC driver a hint as to the number of rows that should be
|
||||
* fetched from the database when more rows are needed for ResultSet.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that internally findEach and findEachWhile will set the fetch size
|
||||
* if it has not already as these queries expect to process a lot of rows.
|
||||
* If we didn't then Postgres and MySql for example would eagerly pull back
|
||||
* all the row data and potentially consume a lot of memory in the process.
|
||||
* </p>
|
||||
* <p>
|
||||
* As findEach and findEachWhile automatically set the fetch size we don't have
|
||||
* to do so generally but we might still wish to for tuning a specific use case.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setBufferFetchSizeHint(int fetchSize);
|
||||
|
||||
@@ -1260,7 +1320,7 @@ public interface Query<T> {
|
||||
* Return true if this query has forUpdate set.
|
||||
*/
|
||||
boolean isForUpdate();
|
||||
|
||||
|
||||
/**
|
||||
* Set root table alias.
|
||||
*/
|
||||
@@ -1274,7 +1334,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Set true if you want to disable lazy loading.
|
||||
* <p>
|
||||
* That is, once the object graph is returned further lazy loading is disabled.
|
||||
* That is, once the object graph is returned further lazy loading is disabled.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
|
||||
* persistence context scope and adjusts jdbc fetch buffer size for large
|
||||
* queries. As such it is better to use findList for small queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
|
||||
* when you have finished iterating the results (typically in a finally block).
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer ...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the underlying resources
|
||||
* it.close();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -606,9 +606,9 @@ public final class RawSql implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
protected static String derivePropertyName(String dbAlias, String dbColumn) {
|
||||
if (dbAlias != null) {
|
||||
return dbAlias;
|
||||
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
|
||||
}
|
||||
int dotPos = dbColumn.indexOf('.');
|
||||
if (dotPos > -1) {
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
|
||||
@@ -26,7 +26,7 @@ package com.avaje.ebean;
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated"
|
||||
* String msg = "There were " + modifiedCount + " rows updated"
|
||||
* </pre>
|
||||
*
|
||||
* @see Update
|
||||
@@ -117,8 +117,7 @@ public interface SqlUpdate {
|
||||
SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position. Exactly the same as
|
||||
* {@link #setNull(int, int)}.
|
||||
* Set a null parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
@@ -143,4 +142,4 @@ public interface SqlUpdate {
|
||||
*/
|
||||
SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,13 +54,52 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commits the transaction at this point with the expectation that another
|
||||
* commit (or rollback or end) will occur later to complete the transaction.
|
||||
* <p>
|
||||
* This is similar to commit() but leaves the transaction "Active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commitAndContinue() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
* <p>
|
||||
* This performs commit and completes the transaction closing underlying resources and
|
||||
* marking the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Flush the JDBC batch buffer</li>
|
||||
* <li>Call commit on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commit() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
* <p>
|
||||
* This performs rollback, closes underlying resources and marks the transaction as "In active".
|
||||
* </p>
|
||||
* <h3>Functions/h3>
|
||||
* <ul>
|
||||
* <li>Call rollback on the underlying JDBC connection</li>
|
||||
* <li>Trigger any registered TransactionCallbacks</li>
|
||||
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
|
||||
* <li>Mark the transaction as "Inactive"</li>
|
||||
* </ul>
|
||||
*/
|
||||
void rollback() throws PersistenceException;
|
||||
|
||||
@@ -74,6 +113,16 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Mark the transaction for rollback only.
|
||||
*/
|
||||
void setRollbackOnly();
|
||||
|
||||
/**
|
||||
* Return true if the transaction is marked as rollback only.
|
||||
*/
|
||||
boolean isRollbackOnly();
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
@@ -417,9 +466,8 @@ public interface Transaction extends Closeable {
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebena and are solely meant as a convenient
|
||||
* method push user information to e.g. the
|
||||
* {@link com.avaje.ebean.event.TransactionEventListener}.
|
||||
* impact on any internals of ebean and are solely meant as a convenient
|
||||
* method push user information (although somewhat replaced by TransactionCallback).
|
||||
*/
|
||||
void putUserObject(String name, Object value);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.ArrayList;
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see TxCallable
|
||||
* @see TxRunnable
|
||||
* @see Ebean#execute(TxScope, TxCallable)
|
||||
@@ -44,27 +44,6 @@ public final class TxScope {
|
||||
|
||||
ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a TxScope with REQUIRES.
|
||||
*/
|
||||
@@ -130,6 +109,44 @@ public final class TxScope {
|
||||
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PersistBatch has been set.
|
||||
*/
|
||||
public boolean isBatchSet() {
|
||||
return batch != null && batch != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch on cascade has been set.
|
||||
*/
|
||||
public boolean isBatchOnCascadeSet() {
|
||||
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if batch size has been set.
|
||||
*/
|
||||
public boolean isBatchSizeSet() {
|
||||
return batchSize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
|
||||
*/
|
||||
public void checkBatchMode() {
|
||||
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
|
||||
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
|
||||
batch = PersistBatch.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the mode is considered not set.
|
||||
*/
|
||||
private boolean notSet(PersistBatch batchMode) {
|
||||
return batchMode == null || batchMode == PersistBatch.INHERIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction type.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for declaring an index on a single column.
|
||||
* An annotation for declaring an index.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Indices.class)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
@@ -27,6 +29,9 @@ public @interface Index {
|
||||
/**
|
||||
* When placed on the class (rather than field) you can specify the columns
|
||||
* to include in the index in order.
|
||||
*
|
||||
* Wnen placed on a field, and columnNames are specified, the field-column has to be included.
|
||||
* You can use "${fa}" for alias
|
||||
*/
|
||||
String[] columnNames() default {};
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
/**
|
||||
* An annotation for declaring multiple indices at class or field level.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Indices {
|
||||
|
||||
/**
|
||||
* Array with {@link Index} definitions.
|
||||
*/
|
||||
Index[] value() default {};
|
||||
}
|
||||
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disableLazyLoad state.
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoad);
|
||||
|
||||
/**
|
||||
* Load bean from another collection.
|
||||
*/
|
||||
|
||||
@@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
/**
|
||||
@@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return embeddedOwnerIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the getter callback.
|
||||
*/
|
||||
public void clearGetterCallback() {
|
||||
this.preGetterCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the callback to be triggered when getter is called.
|
||||
* This is used primarily to automatically flush the JDBC batch.
|
||||
*/
|
||||
public void registerGetterCallback(PreGetterCallback getterCallback) {
|
||||
this.preGetterCallback = getterCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the embedded beans owning bean.
|
||||
*/
|
||||
@@ -325,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return state == STATE_LOADED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean into NEW state.
|
||||
*/
|
||||
public void setNew() {
|
||||
this.state = STATE_NEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loaded state to true.
|
||||
* <p>
|
||||
@@ -832,19 +856,31 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
}
|
||||
|
||||
|
||||
private final void preGetterCallback() {
|
||||
if (preGetterCallback != null) {
|
||||
preGetterCallback.preGetterTrigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called prior to Id property getter.
|
||||
*/
|
||||
public void preGetId() {
|
||||
preGetterCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that is called prior to a getter method on the actual entity.
|
||||
*/
|
||||
public void preGetter(int propertyIndex) {
|
||||
preGetterCallback();
|
||||
if (state == STATE_NEW || disableLazyLoad) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoadedProperty(propertyIndex)) {
|
||||
loadBean(propertyIndex);
|
||||
}
|
||||
|
||||
if (nodeUsageCollector != null) {
|
||||
nodeUsageCollector.addUsed(getProperty(propertyIndex));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* A callback that can be registered to fire on getter method calls.
|
||||
* It's primary purpose is to automatically flush JDBC batch buffer.
|
||||
*/
|
||||
public interface PreGetterCallback {
|
||||
|
||||
/**
|
||||
* Trigger the callback.
|
||||
*/
|
||||
void preGetterTrigger();
|
||||
}
|
||||
@@ -20,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
@@ -84,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
this.filterMany = filterMany;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
this.disableLazyLoad = disableLazyLoad;
|
||||
}
|
||||
|
||||
protected void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
|
||||
@@ -102,7 +102,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
if (modifyListening) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
list = new ArrayList<E>();
|
||||
@@ -114,7 +114,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
if (disableLazyLoad) {
|
||||
list = new ArrayList<E>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
*
|
||||
* @see ServerConfig#addCustomMapping(DbType, String)
|
||||
*/
|
||||
public class CustomDbTypeMapping {
|
||||
|
||||
protected final DbType type;
|
||||
|
||||
protected final String columnDefinition;
|
||||
|
||||
protected final Platform platform;
|
||||
|
||||
/**
|
||||
* Create a mapping.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
this.type = type;
|
||||
this.columnDefinition = columnDefinition;
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mapping that should apply to all the database platforms.
|
||||
*/
|
||||
public CustomDbTypeMapping(DbType type, String columnDefinition) {
|
||||
this(type, columnDefinition, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB type the mapping applies to.
|
||||
*/
|
||||
public DbType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB column definition to use.
|
||||
*/
|
||||
public String getColumnDefinition() {
|
||||
return columnDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform this mapping should apply to. Null means it applied to all platforms.
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.dbmigration.DbMigration;
|
||||
import org.avaje.dbmigration.MigrationConfig;
|
||||
import org.avaje.dbmigration.MigrationRunner;
|
||||
@@ -20,7 +19,7 @@ public class DbMigrationConfig {
|
||||
/**
|
||||
* The database platform to generate migration DDL for.
|
||||
*/
|
||||
protected DbPlatformName platform;
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Set to true if the DB migration should be generated on server start.
|
||||
@@ -112,14 +111,14 @@ public class DbMigrationConfig {
|
||||
* We typically need to explicitly specify this as migration can often be generated
|
||||
* when running against H2.
|
||||
*/
|
||||
public DbPlatformName getPlatform() {
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB platform to generate migration DDL for.
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@@ -366,7 +365,7 @@ public class DbMigrationConfig {
|
||||
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
|
||||
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
|
||||
|
||||
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum DbPlatformName {
|
||||
public enum Platform {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
@@ -7,14 +7,15 @@ import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.cache.ServerCachePlugin;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanPostConstructListener;
|
||||
import com.avaje.ebean.event.BeanPostLoad;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BulkTableEventListener;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
@@ -84,6 +85,8 @@ public class ServerConfig {
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<CustomDbTypeMapping>();
|
||||
|
||||
/**
|
||||
* The underlying properties that were used during configuration.
|
||||
*/
|
||||
@@ -163,6 +166,17 @@ public class ServerConfig {
|
||||
*/
|
||||
private int databaseSequenceBatchSize = 20;
|
||||
|
||||
/**
|
||||
* JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver.
|
||||
*/
|
||||
private int jdbcFetchSizeFindList;
|
||||
|
||||
/**
|
||||
* JDBC fetchSize hint when using findEach/findEachWhile. Defaults to 100. Note that this does
|
||||
* not apply to MySql as that gets special treatment (forward only etc).
|
||||
*/
|
||||
private int jdbcFetchSizeFindEach = 100;
|
||||
|
||||
/**
|
||||
* Suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
@@ -187,9 +201,11 @@ public class ServerConfig {
|
||||
private PersistBatch persistBatch = PersistBatch.NONE;
|
||||
|
||||
/**
|
||||
* Use for per request batch mode.
|
||||
* Use for cascade persist JDBC batch mode. INHERIT means use the platform default
|
||||
* which is ALL except for SQL Server where it is NONE (as getGeneratedKeys isn't
|
||||
* supported on SQL Server with JDBC batch).
|
||||
*/
|
||||
private PersistBatch persistBatchOnCascade = PersistBatch.NONE;
|
||||
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
|
||||
|
||||
private int persistBatchSize = 20;
|
||||
|
||||
@@ -307,18 +323,18 @@ public class ServerConfig {
|
||||
/**
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
|
||||
*/
|
||||
private DbUuid dbUuid = DbUuid.AUTO;
|
||||
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
|
||||
|
||||
|
||||
private List<IdGenerator> idGenerators = new ArrayList<IdGenerator>();
|
||||
private List<BeanFindController> findControllers = new ArrayList<BeanFindController>();
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPostLoad> postLoaders = new ArrayList<BeanPostLoad>();
|
||||
private List<BeanPostConstructListener> postConstructListeners = new ArrayList<BeanPostConstructListener>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
|
||||
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
|
||||
|
||||
/**
|
||||
* By default inserts are included in the change log.
|
||||
@@ -366,19 +382,13 @@ public class ServerConfig {
|
||||
|
||||
private boolean transactionRollbackOnChecked = true;
|
||||
|
||||
private boolean registerJmxMBeans = true;
|
||||
|
||||
// configuration for the background executor service (thread pool)
|
||||
|
||||
private int backgroundExecutorSchedulePoolSize = 1;
|
||||
private int backgroundExecutorCorePoolSize = 1;
|
||||
private int backgroundExecutorMaxPoolSize = 8;
|
||||
private int backgroundExecutorIdleSecs = 60;
|
||||
private int backgroundExecutorShutdownSecs = 30;
|
||||
|
||||
// defaults for the L2 bean caching
|
||||
|
||||
private int cacheWarmingDelay = 30;
|
||||
private int cacheMaxSize = 10000;
|
||||
private int cacheMaxIdleTime = 600;
|
||||
private int cacheMaxTimeToLive = 60 * 60 * 6;
|
||||
@@ -396,7 +406,7 @@ public class ServerConfig {
|
||||
private boolean expressionEqualsWithNullAsNoop;
|
||||
|
||||
/**
|
||||
* Set to true to use native ILIKE expression (if support by datasbase platform / like Postgres).
|
||||
* Set to true to use native ILIKE expression (if support by database platform / like Postgres).
|
||||
*/
|
||||
private boolean expressionNativeIlike;
|
||||
|
||||
@@ -719,6 +729,34 @@ public class ServerConfig {
|
||||
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default JDBC fetchSize hint for findList queries.
|
||||
*/
|
||||
public int getJdbcFetchSizeFindList() {
|
||||
return jdbcFetchSizeFindList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default JDBC fetchSize hint for findList queries.
|
||||
*/
|
||||
public void setJdbcFetchSizeFindList(int jdbcFetchSizeFindList) {
|
||||
this.jdbcFetchSizeFindList = jdbcFetchSizeFindList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default JDBC fetchSize hint for findEach/findEachWhile queries.
|
||||
*/
|
||||
public int getJdbcFetchSizeFindEach() {
|
||||
return jdbcFetchSizeFindEach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default JDBC fetchSize hint for findEach/findEachWhile queries.
|
||||
*/
|
||||
public void setJdbcFetchSizeFindEach(int jdbcFetchSizeFindEach) {
|
||||
this.jdbcFetchSizeFindEach = jdbcFetchSizeFindEach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ChangeLogPrepare.
|
||||
* <p>
|
||||
@@ -1001,20 +1039,6 @@ public class ServerConfig {
|
||||
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the server should register JMX MBeans.
|
||||
*/
|
||||
public boolean isRegisterJmxMBeans() {
|
||||
return registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the server should register JMX MBeans.
|
||||
*/
|
||||
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
|
||||
this.registerJmxMBeans = registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor schedule pool size. Defaults to 1.
|
||||
*/
|
||||
@@ -1029,48 +1053,6 @@ public class ServerConfig {
|
||||
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor core pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorCorePoolSize() {
|
||||
return backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor core pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
|
||||
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor max pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorMaxPoolSize() {
|
||||
return backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor max pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
|
||||
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor idle seconds.
|
||||
*/
|
||||
public int getBackgroundExecutorIdleSecs() {
|
||||
return backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor idle seconds.
|
||||
*/
|
||||
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
|
||||
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
@@ -1087,20 +1069,6 @@ public class ServerConfig {
|
||||
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache warming delay in seconds.
|
||||
*/
|
||||
public int getCacheWarmingDelay() {
|
||||
return cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache warming delay in seconds.
|
||||
*/
|
||||
public void setCacheWarmingDelay(int cacheWarmingDelay) {
|
||||
this.cacheWarmingDelay = cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max size.
|
||||
*/
|
||||
@@ -1474,7 +1442,7 @@ public class ServerConfig {
|
||||
* <p>
|
||||
* You can also set this in ebean.proprerties:
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* # set via ebean.properties
|
||||
* ebean.encryptKeyManager=com.avaje.tests.basic.encrypt.BasicEncyptKeyManager
|
||||
@@ -1807,7 +1775,7 @@ public class ServerConfig {
|
||||
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
|
||||
* on the transaction.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
@@ -1969,6 +1937,54 @@ public class ServerConfig {
|
||||
this.resourceDirectory = resourceDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String.class/varchar but only for Postgres
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
* @param platform Optionally specify the platform this mapping should apply to.
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
|
||||
*
|
||||
* // set the default mapping for String/varchar
|
||||
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The DB type this mapping should apply to
|
||||
* @param columnDefinition The column definition that should be used
|
||||
*/
|
||||
public void addCustomMapping(DbType type, String columnDefinition) {
|
||||
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of custom type mappings.
|
||||
*/
|
||||
public List<CustomDbTypeMapping> getCustomTypeMappings() {
|
||||
return customDbTypeMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanQueryAdapter instance.
|
||||
* <p>
|
||||
@@ -2041,6 +2057,16 @@ public class ServerConfig {
|
||||
postLoaders.add(postLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanPostConstructListener instance.
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #setPostConstructListeners(List)} to set
|
||||
* all the BeanPostConstructListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(BeanPostConstructListener listener) {
|
||||
postConstructListeners.add(listener);
|
||||
}
|
||||
/**
|
||||
* Return the list of BeanFindController instances.
|
||||
*/
|
||||
@@ -2069,6 +2095,19 @@ public class ServerConfig {
|
||||
this.postLoaders = postLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanPostLoader instances.
|
||||
*/
|
||||
public List<BeanPostConstructListener> getPostConstructListeners() {
|
||||
return postConstructListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of BeanPostLoader instances.
|
||||
*/
|
||||
public void setPostConstructListeners(List<BeanPostConstructListener> listeners) {
|
||||
this.postConstructListeners = listeners;
|
||||
}
|
||||
/**
|
||||
* Return the BeanPersistController instances.
|
||||
*/
|
||||
@@ -2087,35 +2126,6 @@ public class ServerConfig {
|
||||
this.persistControllers = persistControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionEventListener instance
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #setTransactionEventListeners(List)}
|
||||
* to set all the TransactionEventListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(TransactionEventListener listener) {
|
||||
transactionEventListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TransactionEventListener instances.
|
||||
*/
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
return transactionEventListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all the TransactionEventListener instances.
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #add(TransactionEventListener)} to
|
||||
* add TransactionEventListener instances one at a time.
|
||||
* </p>
|
||||
*/
|
||||
public void setTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
this.transactionEventListeners = transactionEventListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanPersistListener instance.
|
||||
* <p>
|
||||
@@ -2358,6 +2368,8 @@ public class ServerConfig {
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
|
||||
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
|
||||
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
|
||||
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
|
||||
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
|
||||
@@ -2367,7 +2379,6 @@ public class ServerConfig {
|
||||
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
|
||||
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
|
||||
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
|
||||
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
|
||||
|
||||
if (packages != null) {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
@@ -2405,6 +2416,8 @@ public class ServerConfig {
|
||||
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
|
||||
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
|
||||
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
@@ -2489,13 +2502,14 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the PersistBatch mode to use for 'batchOnCascade' taking into account if the database
|
||||
* platform supports getGeneratedKeys in batch mode.
|
||||
* <p>
|
||||
* Used to effectively turn off batchOnCascade for SQL Server - still allows explicit batch mode.
|
||||
* </p>
|
||||
*/
|
||||
public PersistBatch appliedPersistBatchOnCascade() {
|
||||
|
||||
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
|
||||
if (persistBatchOnCascade == PersistBatch.INHERIT) {
|
||||
// use the platform default (ALL except SQL Server which has NONE)
|
||||
return databasePlatform.getPersistBatchOnCascade();
|
||||
}
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2571,18 +2585,45 @@ public class ServerConfig {
|
||||
public enum DbUuid {
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres.
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
AUTO,
|
||||
AUTO_VARCHAR(true, false),
|
||||
|
||||
/**
|
||||
* Store using DB VARCHAR.
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
|
||||
*/
|
||||
VARCHAR,
|
||||
AUTO_BINARY(true, true),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY.
|
||||
* Store using DB VARCHAR(40).
|
||||
*/
|
||||
BINARY
|
||||
VARCHAR(false, false),
|
||||
|
||||
/**
|
||||
* Store using DB BINARY(16).
|
||||
*/
|
||||
BINARY(false, true);
|
||||
|
||||
boolean nativeType;
|
||||
boolean binary;
|
||||
|
||||
DbUuid(boolean nativeType, boolean binary) {
|
||||
this.nativeType = nativeType;
|
||||
this.binary = binary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if native UUID type is preferred.
|
||||
*/
|
||||
public boolean useNativeType() {
|
||||
return nativeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
|
||||
*/
|
||||
public boolean useBinary() {
|
||||
return binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ public class DB2Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
booleanDbType = Types.BOOLEAN;
|
||||
dbTypeMap.put(Types.REAL, new DbType("real"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.config.CustomDbTypeMapping;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
@@ -14,7 +17,6 @@ import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Database platform specific settings.
|
||||
@@ -33,12 +35,6 @@ public class DatabasePlatform {
|
||||
*/
|
||||
ROLLBACK,
|
||||
|
||||
/**
|
||||
* Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
|
||||
* as a performance optimisation.
|
||||
*/
|
||||
CLOSE,
|
||||
|
||||
/**
|
||||
* Commit the transaction
|
||||
*/
|
||||
@@ -79,7 +75,7 @@ public class DatabasePlatform {
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
protected DbPlatformTypeMapping dbTypeMap = new DbPlatformTypeMapping();
|
||||
|
||||
/**
|
||||
* Default values for DB columns.
|
||||
@@ -155,11 +151,9 @@ public class DatabasePlatform {
|
||||
protected boolean forwardOnlyHintOnFindIterate;
|
||||
|
||||
/**
|
||||
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
|
||||
* batch mode (meaning for batch inserts you should explicitly turn off
|
||||
* getGeneratedKeys - joy).
|
||||
* By default we use JDBC batch when cascading (except for SQL Server).
|
||||
*/
|
||||
protected boolean disallowBatchOnCascade;
|
||||
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
|
||||
|
||||
protected PlatformDdl platformDdl;
|
||||
|
||||
@@ -183,8 +177,24 @@ public class DatabasePlatform {
|
||||
public DatabasePlatform() {
|
||||
}
|
||||
|
||||
public void configure(Properties properties) {
|
||||
// by default do nothing
|
||||
/**
|
||||
* Configure UUID Storage etc based on ServerConfig settings.
|
||||
*/
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
dbTypeMap.config(nativeUuidType, serverConfig.getDbUuid());
|
||||
for (CustomDbTypeMapping mapping : serverConfig.getCustomTypeMappings()) {
|
||||
if (platformMatch(mapping.getPlatform())) {
|
||||
dbTypeMap.put(mapping.getType(), parse(mapping.getColumnDefinition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformType.parse(columnDefinition);
|
||||
}
|
||||
|
||||
private boolean platformMatch(Platform platform) {
|
||||
return platform == null || platform.name().equalsIgnoreCase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,7 +324,7 @@ public class DatabasePlatform {
|
||||
*
|
||||
* @return the db type map
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
public DbPlatformTypeMapping getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
@@ -542,14 +552,10 @@ public class DatabasePlatform {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persistBatchOnCascade setting should be ignored.
|
||||
* <p>
|
||||
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
|
||||
* so can't really be transparently used.
|
||||
* </p>
|
||||
* Return the platform default JDBC batch mode for persist cascade.
|
||||
*/
|
||||
public boolean isDisallowBatchOnCascade() {
|
||||
return disallowBatchOnCascade;
|
||||
public PersistBatch getPersistBatchOnCascade() {
|
||||
return persistBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Represents a DB type with name, length, precision, and scale.
|
||||
* <p>
|
||||
* The length is for VARCHAR types and precision/scale for DECIMAL types.
|
||||
* </p>
|
||||
*/
|
||||
public class DbPlatformType implements ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* The data type name (VARCHAR, INTEGER ...)
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The default length or precision.
|
||||
*/
|
||||
private final int defaultLength;
|
||||
|
||||
/**
|
||||
* The default scale (decimal).
|
||||
*/
|
||||
private final int defaultScale;
|
||||
|
||||
/**
|
||||
* Set to true if the type should never have a length or scale.
|
||||
*/
|
||||
private final boolean canHaveLength;
|
||||
|
||||
/**
|
||||
* Parse a type definition into a DbPlatformType.
|
||||
* <p>
|
||||
* e.g. "decimal(18,6)"
|
||||
* e.g. "text"
|
||||
* </p>
|
||||
*/
|
||||
public static DbPlatformType parse(String columnDefinition) {
|
||||
return DbPlatformTypeParser.parse(columnDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with no length or scale.
|
||||
*/
|
||||
public DbPlatformType(String name) {
|
||||
this(name, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given length.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultLength) {
|
||||
this(name, defaultLength, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for Decimal with precision and scale.
|
||||
*/
|
||||
public DbPlatformType(String name, int defaultPrecision, int defaultScale) {
|
||||
this.name = name;
|
||||
this.defaultLength = defaultPrecision;
|
||||
this.defaultScale = defaultScale;
|
||||
this.canHaveLength = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with canHaveLength=false for types that should never have a length.
|
||||
*
|
||||
* @param name
|
||||
* the type name
|
||||
* @param canHaveLength
|
||||
* set this to false for type that should never have a length
|
||||
*/
|
||||
public DbPlatformType(String name, boolean canHaveLength) {
|
||||
this.name = name;
|
||||
this.defaultLength = 0;
|
||||
this.defaultScale = 0;
|
||||
this.canHaveLength = canHaveLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default length/precision.
|
||||
*/
|
||||
public int getDefaultLength() {
|
||||
return defaultLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default scale.
|
||||
*/
|
||||
public int getDefaultScale() {
|
||||
return defaultScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a specific property that incorporates the name, length,
|
||||
* precision and scale.
|
||||
* <p>
|
||||
* The deployLength and deployScale are for the property we are rendering the
|
||||
* DB type for.
|
||||
* </p>
|
||||
*
|
||||
* @param deployLength
|
||||
* the length or precision defined by deployment on a specific
|
||||
* property.
|
||||
* @param deployScale
|
||||
* the scale defined by deployment on a specific property.
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale) {
|
||||
return renderType(deployLength, deployScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the type defining strict mode.
|
||||
* <p>
|
||||
* If strict mode if OFF then this will render with a scale value even if
|
||||
* that is not strictly supported. The reason for supporting this is to enable
|
||||
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
|
||||
* Postgres and VARCHAR(200) for other databases.
|
||||
* </p>
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale, boolean strict) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
|
||||
if (canHaveLength || !strict) {
|
||||
// see if there is a precision/scale to add (or not)
|
||||
int len = deployLength != 0 ? deployLength : defaultLength;
|
||||
if (len > 0) {
|
||||
sb.append("(");
|
||||
sb.append(len);
|
||||
int scale = deployScale != 0 ? deployScale : defaultScale;
|
||||
if (scale > 0) {
|
||||
sb.append(",");
|
||||
sb.append(scale);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the type with a new default length.
|
||||
*/
|
||||
public DbPlatformType withLength(int defaultLength) {
|
||||
return new DbPlatformType(name, defaultLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper to reverse lookup a DbType given the name or JDBC int value.
|
||||
*/
|
||||
class DbPlatformTypeLookup {
|
||||
|
||||
/**
|
||||
* A map to lookup the type by name.
|
||||
*/
|
||||
private Map<String, DbType> nameLookup = new HashMap<String, DbType>();
|
||||
|
||||
/**
|
||||
* A map to lookup the type by JDBC int value.
|
||||
*/
|
||||
private Map<Integer, DbType> idLookup = new HashMap<Integer, DbType>();
|
||||
|
||||
DbPlatformTypeLookup() {
|
||||
addAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byName(String name) {
|
||||
return nameLookup.get(name.trim().toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DbType for the given name.
|
||||
*/
|
||||
DbType byId(int jdbcId) {
|
||||
return idLookup.get(jdbcId);
|
||||
}
|
||||
|
||||
private void addAll() {
|
||||
// Extra mapping for Float and Varchar2
|
||||
add("FLOAT", DbType.REAL);
|
||||
add("VARCHAR2", DbType.VARCHAR);
|
||||
for (DbType type : DbType.values()) {
|
||||
add(type.name(), type);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(String name, DbType dbType) {
|
||||
nameLookup.put(name, dbType);
|
||||
idLookup.put(dbType.id(), dbType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to map bean property types to DB specific types for DDL generation.
|
||||
*/
|
||||
public class DbPlatformTypeMapping {
|
||||
|
||||
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
|
||||
private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
|
||||
private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
|
||||
private static final DbPlatformType JSON_VARCHAR_PLACEHOLDER = new DbPlatformType("jsonVarcharPlaceholder");
|
||||
|
||||
private final Map<DbType, DbPlatformType> typeMap = new HashMap<DbType, DbPlatformType>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
* <p>
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbPlatformTypeMapping logicalTypes() {
|
||||
return new DbPlatformTypeMapping(true);
|
||||
}
|
||||
|
||||
public DbPlatformTypeMapping() {
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbPlatformTypeMapping(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(DbType.BOOLEAN);
|
||||
put(DbType.BIT);
|
||||
put(DbType.INTEGER);
|
||||
put(DbType.BIGINT);
|
||||
put(DbType.DOUBLE);
|
||||
put(DbType.SMALLINT);
|
||||
put(DbType.TINYINT);
|
||||
put(DbType.BLOB);
|
||||
put(DbType.CLOB);
|
||||
put(DbType.ARRAY);
|
||||
put(DbType.DATE);
|
||||
put(DbType.TIME);
|
||||
put(DbType.TIMESTAMP);
|
||||
put(DbType.LONGVARBINARY);
|
||||
put(DbType.LONGVARCHAR);
|
||||
// most commonly real maps to db float
|
||||
put(DbType.REAL, new DbPlatformType("float"));
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar"));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal"));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary"));
|
||||
put(DbType.BINARY, new DbPlatformType("binary"));
|
||||
put(DbType.CHAR, new DbPlatformType("char"));
|
||||
|
||||
put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
put(DbType.JSON, new DbPlatformType("json", false));
|
||||
put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
put(DbType.JSONCLOB, new DbPlatformType("jsonclob"));
|
||||
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
put(DbType.CHAR, new DbPlatformType("char", 1));
|
||||
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
|
||||
put(DbType.UUID, UUID_PLACEHOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbPlatformType lookup(String name, boolean withScale) {
|
||||
|
||||
DbType type = lookup.byName(name);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (type) {
|
||||
case JSONBLOB:
|
||||
return get(DbType.BLOB);
|
||||
case JSONCLOB:
|
||||
return get(DbType.CLOB);
|
||||
case JSONVARCHAR:
|
||||
return get(DbType.VARCHAR);
|
||||
case JSON:
|
||||
return getJsonType(DbType.JSON, withScale);
|
||||
case JSONB:
|
||||
return getJsonType(DbType.JSONB, withScale);
|
||||
default:
|
||||
return get(type);
|
||||
}
|
||||
}
|
||||
|
||||
private DbPlatformType getJsonType(DbType type, boolean withScale) {
|
||||
|
||||
DbPlatformType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
return withScale ? get(DbType.VARCHAR) : get(DbType.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(DbType.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(DbType.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
private void put(DbType type) {
|
||||
typeMap.put(type, type.createPlatformType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(DbType type, DbPlatformType platformType) {
|
||||
typeMap.put(type, platformType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(int jdbcType) {
|
||||
return get(lookup.byId(jdbcType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbPlatformType get(DbType dbType) {
|
||||
return typeMap.get(dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
|
||||
*/
|
||||
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
|
||||
if (nativeUuidType && dbUuid.useNativeType()) {
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
} else if (dbUuid.useBinary()) {
|
||||
put(DbType.UUID, get(DbType.BINARY).withLength(16));
|
||||
} else {
|
||||
put(DbType.UUID, get(DbType.VARCHAR).withLength(40));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Parse raw column definitions into DbPlatformType like "decimal(18,6)" and "varchar(20) and "json".
|
||||
*/
|
||||
class DbPlatformTypeParser {
|
||||
|
||||
/**
|
||||
* Parse the column definition and return the DbPlatformType.
|
||||
*/
|
||||
static DbPlatformType parse(String columnDefinition) {
|
||||
|
||||
columnDefinition = columnDefinition.trim();
|
||||
|
||||
int openPos = columnDefinition.indexOf('(');
|
||||
if (openPos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
int closePos = columnDefinition.indexOf(')', openPos);
|
||||
if (closePos == -1) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
try {
|
||||
int commaPos = columnDefinition.indexOf(',', openPos);
|
||||
if (commaPos > -1) {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, commaPos));
|
||||
int precision = Integer.parseInt(columnDefinition.substring(commaPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale, precision);
|
||||
|
||||
} else {
|
||||
String type = columnDefinition.substring(0, openPos);
|
||||
int scale = Integer.parseInt(columnDefinition.substring(openPos + 1, closePos));
|
||||
return new DbPlatformType(type, scale);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return new DbPlatformType(columnDefinition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +1,65 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Represents a DB type with name, length, precision, and scale.
|
||||
* The known DB types that are mapped.
|
||||
* <p>
|
||||
* The length is for VARCHAR types and precision/scale for DECIMAL types.
|
||||
* This includes extra types such as UUID, JSON, JSONB and HSTORE.
|
||||
* </p>
|
||||
*/
|
||||
public class DbType {
|
||||
public enum DbType {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
public static final int UUID = 5010;
|
||||
BOOLEAN(Types.BOOLEAN),
|
||||
BIT(Types.BIT),
|
||||
INTEGER(Types.INTEGER),
|
||||
BIGINT(Types.BIGINT),
|
||||
SMALLINT(Types.SMALLINT),
|
||||
TINYINT(Types.TINYINT),
|
||||
REAL(Types.REAL),
|
||||
//FLOAT(Types.FLOAT),
|
||||
DOUBLE(Types.DOUBLE),
|
||||
DECIMAL(Types.DECIMAL),
|
||||
VARCHAR(Types.VARCHAR),
|
||||
CHAR(Types.CHAR),
|
||||
BLOB(Types.BLOB),
|
||||
CLOB(Types.CLOB),
|
||||
LONGVARBINARY(Types.LONGVARBINARY),
|
||||
LONGVARCHAR(Types.LONGVARCHAR),
|
||||
VARBINARY(Types.VARBINARY),
|
||||
BINARY(Types.BINARY),
|
||||
DATE(Types.DATE),
|
||||
TIME(Types.TIME),
|
||||
TIMESTAMP(Types.TIMESTAMP),
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
public static final int HSTORE = 5000;
|
||||
ARRAY(Types.ARRAY),
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSON type.
|
||||
*/
|
||||
public static final int JSON = 5001;
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSONB type.
|
||||
*/
|
||||
public static final int JSONB = 5002;
|
||||
HSTORE(ExtraDbTypes.HSTORE),
|
||||
JSON(ExtraDbTypes.JSON),
|
||||
JSONB(ExtraDbTypes.JSONB),
|
||||
JSONCLOB(ExtraDbTypes.JSONClob),
|
||||
JSONBLOB(ExtraDbTypes.JSONBlob),
|
||||
JSONVARCHAR(ExtraDbTypes.JSONVarchar);
|
||||
|
||||
/**
|
||||
* Type to map JSON content to VARCHAR.
|
||||
*/
|
||||
public static final int JSONVarchar = 5003;
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob.
|
||||
*/
|
||||
public static final int JSONClob = 5004;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Blob.
|
||||
*/
|
||||
public static final int JSONBlob = 5005;
|
||||
|
||||
/**
|
||||
* The data type name (VARCHAR, INTEGER ...)
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The default length or precision.
|
||||
*/
|
||||
private final int defaultLength;
|
||||
|
||||
/**
|
||||
* The default scale (decimal).
|
||||
*/
|
||||
private final int defaultScale;
|
||||
|
||||
/**
|
||||
* Set to true if the type should never have a length or scale.
|
||||
*/
|
||||
private final boolean canHaveLength;
|
||||
|
||||
/**
|
||||
* Construct with no length or scale.
|
||||
*/
|
||||
public DbType(String name) {
|
||||
this(name, 0, 0);
|
||||
DbType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given length.
|
||||
* Return the JDBC java.sql.Types value.
|
||||
*/
|
||||
public DbType(String name, int defaultLength) {
|
||||
this(name, defaultLength, 0);
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for Decimal with precision and scale.
|
||||
* Create a platform type without scale or precision.
|
||||
*/
|
||||
public DbType(String name, int defaultPrecision, int defaultScale) {
|
||||
this.name = name;
|
||||
this.defaultLength = defaultPrecision;
|
||||
this.defaultScale = defaultScale;
|
||||
this.canHaveLength = true;
|
||||
public DbPlatformType createPlatformType() {
|
||||
return new DbPlatformType(name().toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with canHaveLength=false for types that should never have a length.
|
||||
*
|
||||
* @param name
|
||||
* the type name
|
||||
* @param canHaveLength
|
||||
* set this to false for type that should never have a length
|
||||
*/
|
||||
public DbType(String name, boolean canHaveLength) {
|
||||
this.name = name;
|
||||
this.defaultLength = 0;
|
||||
this.defaultScale = 0;
|
||||
this.canHaveLength = canHaveLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a specific property that incorporates the name, length,
|
||||
* precision and scale.
|
||||
* <p>
|
||||
* The deployLength and deployScale are for the property we are rendering the
|
||||
* DB type for.
|
||||
* </p>
|
||||
*
|
||||
* @param deployLength
|
||||
* the length or precision defined by deployment on a specific
|
||||
* property.
|
||||
* @param deployScale
|
||||
* the scale defined by deployment on a specific property.
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale) {
|
||||
return renderType(deployLength, deployScale, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the type defining strict mode.
|
||||
* <p>
|
||||
* If strict mode if OFF then this will render with a scale value even if
|
||||
* that is not strictly supported. The reason for supporting this is to enable
|
||||
* use to use types like jsonb(200) as a "logical" type that maps to JSONB for
|
||||
* Postgres and VARCHAR(200) for other databases.
|
||||
* </p>
|
||||
*/
|
||||
public String renderType(int deployLength, int deployScale, boolean strict) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name);
|
||||
|
||||
if (canHaveLength || !strict) {
|
||||
// see if there is a precision/scale to add (or not)
|
||||
int len = deployLength != 0 ? deployLength : defaultLength;
|
||||
if (len > 0) {
|
||||
sb.append("(");
|
||||
sb.append(len);
|
||||
int scale = deployScale != 0 ? deployScale : defaultScale;
|
||||
if (scale > 0) {
|
||||
sb.append(",");
|
||||
sb.append(scale);
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to map bean property types to DB specific types for DDL generation.
|
||||
*/
|
||||
public class DbTypeMap {
|
||||
|
||||
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
|
||||
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
|
||||
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
|
||||
|
||||
/**
|
||||
* A map to reverse lookup the type by name.
|
||||
* <p>
|
||||
* Used when converting from logical types to platform types which we
|
||||
* want to do with 2 phase DDL generation.
|
||||
*/
|
||||
static Map<String, Integer> lookup = new HashMap<String, Integer>();
|
||||
|
||||
static {
|
||||
lookup.put("BOOLEAN", Types.BOOLEAN);
|
||||
lookup.put("BIT", Types.BIT);
|
||||
lookup.put("INTEGER", Types.INTEGER);
|
||||
lookup.put("BIGINT", Types.BIGINT);
|
||||
lookup.put("REAL", Types.REAL);
|
||||
// Float is most common REAL mapping to have that as well
|
||||
lookup.put("FLOAT", Types.REAL);
|
||||
|
||||
lookup.put("DOUBLE", Types.DOUBLE);
|
||||
lookup.put("SMALLINT", Types.SMALLINT);
|
||||
lookup.put("TINYINT", Types.TINYINT);
|
||||
lookup.put("DECIMAL", Types.DECIMAL);
|
||||
lookup.put("VARCHAR", Types.VARCHAR);
|
||||
// VARCHAR2 - extra for Oracle specific column definition
|
||||
lookup.put("VARCHAR2", Types.VARCHAR);
|
||||
lookup.put("CHAR", Types.CHAR);
|
||||
lookup.put("BLOB", Types.BLOB);
|
||||
lookup.put("CLOB", Types.CLOB);
|
||||
|
||||
lookup.put("LONGVARBINARY", Types.LONGVARBINARY);
|
||||
lookup.put("LONGVARCHAR", Types.LONGVARCHAR);
|
||||
lookup.put("VARBINARY", Types.VARBINARY);
|
||||
lookup.put("BINARY", Types.BINARY);
|
||||
lookup.put("DATE", Types.DATE);
|
||||
lookup.put("TIME", Types.TIME);
|
||||
lookup.put("TIMESTAMP", Types.TIMESTAMP);
|
||||
|
||||
lookup.put("ARRAY", Types.ARRAY);
|
||||
lookup.put("UUID", DbType.UUID);
|
||||
|
||||
// Not standard java.sql.Types
|
||||
// logical JSON storage types
|
||||
lookup.put("JSON", DbType.JSON);
|
||||
lookup.put("JSONB", DbType.JSONB);
|
||||
lookup.put("JSONCLOB", DbType.JSONClob);
|
||||
lookup.put("JSONBLOB", DbType.JSONBlob);
|
||||
lookup.put("JSONVARCHAR", DbType.JSONVarchar);
|
||||
}
|
||||
|
||||
|
||||
private final Map<Integer, DbType> typeMap = new HashMap<Integer, DbType>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
*
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbTypeMap logicalTypes() {
|
||||
return new DbTypeMap(true);
|
||||
}
|
||||
|
||||
public DbTypeMap() {
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbTypeMap(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(Types.BOOLEAN, new DbType("boolean"));
|
||||
put(Types.BIT, new DbType("bit"));
|
||||
|
||||
put(Types.INTEGER, new DbType("integer"));
|
||||
put(Types.BIGINT, new DbType("bigint"));
|
||||
put(Types.REAL, new DbType("float"));
|
||||
put(Types.DOUBLE, new DbType("double"));
|
||||
put(Types.SMALLINT, new DbType("smallint"));
|
||||
put(Types.TINYINT, new DbType("tinyint"));
|
||||
put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
|
||||
put(Types.VARCHAR, new DbType("varchar", 255));
|
||||
put(Types.CHAR, new DbType("char", 1));
|
||||
|
||||
put(Types.BLOB, new DbType("blob"));
|
||||
put(Types.CLOB, new DbType("clob"));
|
||||
|
||||
// DB native UUID support (H2 and Postgres)
|
||||
put(DbType.UUID, new DbType("uuid"));
|
||||
put(Types.ARRAY, new DbType("array"));
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.HSTORE, new DbType("hstore", false));
|
||||
put(DbType.JSON, new DbType("json", false));
|
||||
put(DbType.JSONB, new DbType("jsonb", false));
|
||||
put(DbType.JSONClob, new DbType("jsonclob"));
|
||||
put(DbType.JSONBlob, new DbType("jsonblob"));
|
||||
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
|
||||
|
||||
} else {
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
|
||||
}
|
||||
|
||||
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
|
||||
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
|
||||
put(Types.VARBINARY, new DbType("varbinary", 255));
|
||||
put(Types.BINARY, new DbType("binary", 255));
|
||||
|
||||
put(Types.DATE, new DbType("date"));
|
||||
put(Types.TIME, new DbType("time"));
|
||||
put(Types.TIMESTAMP, new DbType("timestamp"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbType lookup(String name, boolean withScale) {
|
||||
name = name.trim().toUpperCase();
|
||||
Integer typeKey = lookup.get(name);
|
||||
if (typeKey == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (typeKey) {
|
||||
case DbType.JSONBlob:
|
||||
return get(Types.BLOB);
|
||||
case DbType.JSONClob:
|
||||
return get(Types.CLOB);
|
||||
case DbType.JSONVarchar:
|
||||
return get(Types.VARCHAR);
|
||||
case DbType.JSON:
|
||||
return getJsonType(DbType.JSON, withScale);
|
||||
case DbType.JSONB:
|
||||
return getJsonType(DbType.JSONB, withScale);
|
||||
default:
|
||||
return get(typeKey);
|
||||
}
|
||||
}
|
||||
|
||||
private DbType getJsonType(int type, boolean withScale) {
|
||||
DbType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
// if we have scale that implies this maps to varchar
|
||||
return withScale ? get(Types.VARCHAR) : get(Types.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(Types.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(Types.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(int jdbcType, DbType dbType) {
|
||||
typeMap.put(jdbcType, dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbType get(int jdbcType) {
|
||||
return typeMap.get(jdbcType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Integer codes for the extra types beyond java.sql.Types.
|
||||
*/
|
||||
public interface ExtraDbTypes {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
int UUID = 5010;
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
int HSTORE = 5000;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSON type.
|
||||
*/
|
||||
int JSON = 5001;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob or Postgres JSONB type.
|
||||
*/
|
||||
int JSONB = 5002;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to VARCHAR.
|
||||
*/
|
||||
int JSONVarchar = 5003;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Clob.
|
||||
*/
|
||||
int JSONClob = 5004;
|
||||
|
||||
/**
|
||||
* Type to map JSON content to Blob.
|
||||
*/
|
||||
int JSONBlob = 5005;
|
||||
|
||||
}
|
||||
@@ -9,9 +9,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H2 database trigger used to populate history tables to support the @History feature.
|
||||
@@ -54,7 +52,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
|
||||
|
||||
int count = 0;
|
||||
List<String> columns = new ArrayList<String>();
|
||||
while (rs.next()) {
|
||||
if (++count > 1) {
|
||||
insertSql.append(",");
|
||||
@@ -66,7 +63,6 @@ public class H2HistoryTrigger implements Trigger {
|
||||
this.effectEndPosition = count - 1;
|
||||
}
|
||||
insertSql.append(columnName);
|
||||
columns.add(columnName);
|
||||
}
|
||||
insertSql.append(") values (");
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -19,9 +21,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.nativeUuidType = true;
|
||||
this.dbDefaultValue.setNow("now()");
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
@@ -34,6 +34,18 @@ public class H2Platform extends DatabasePlatform {
|
||||
// so no changes to dbTypeMap required
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
super.configure(serverConfig);
|
||||
Properties properties = serverConfig.getProperties();
|
||||
if (properties != null) {
|
||||
String idType = properties.getProperty("ebean.h2.idtype");
|
||||
if (idType != null) {
|
||||
this.dbIdentity.setIdType(IdType.valueOf(idType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a H2 specific sequence IdGenerator that supports batch fetching
|
||||
* sequence values.
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -22,7 +21,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server 2000 specific platform.
|
||||
@@ -18,6 +18,7 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
|
||||
public MsSqlServer2000Platform() {
|
||||
super();
|
||||
this.name = "mssqlserver2000";
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
|
||||
@@ -26,22 +27,22 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("image"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
|
||||
|
||||
dbTypeMap.put(Types.DATE, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime"));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server 2005 specific platform.
|
||||
* <p>
|
||||
@@ -21,7 +20,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.name = "mssqlserver2005";
|
||||
// effectively disable persistBatchOnCascade mode for SQL Server
|
||||
// due to lack of support for getGeneratedKeys in batch mode
|
||||
this.disallowBatchOnCascade = true;
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
|
||||
@@ -33,23 +32,23 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("image"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
|
||||
|
||||
dbTypeMap.put(Types.DATE, new DbType("date"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("time"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime2"));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("date"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("time"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
|
||||
* If no deployment length is defined longblob is used.
|
||||
* </p>
|
||||
*/
|
||||
public class MySqlBlob extends DbType {
|
||||
public class MySqlBlob extends DbPlatformType {
|
||||
|
||||
private static final int POWER_2_16 = 65536;
|
||||
private static final int POWER_2_24 = 16777216;
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.avaje.ebean.config.dbplatform;
|
||||
* If no deployment length is defined longtext is used.
|
||||
* </p>
|
||||
*/
|
||||
public class MySqlClob extends DbType {
|
||||
public class MySqlClob extends DbPlatformType {
|
||||
|
||||
private static final int POWER_2_16 = 65536;
|
||||
private static final int POWER_2_24 = 16777216;
|
||||
|
||||
@@ -39,13 +39,13 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.forwardOnlyHintOnFindIterate = true;
|
||||
this.booleanDbType = Types.BIT;
|
||||
|
||||
dbTypeMap.put(Types.BIT, new DbType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime(6)"));
|
||||
dbTypeMap.put(Types.CLOB, new MySqlClob());
|
||||
dbTypeMap.put(Types.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(Types.BINARY, new DbType("binary", 255));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255));
|
||||
dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1) default 0"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
|
||||
dbTypeMap.put(DbType.CLOB, new MySqlClob());
|
||||
dbTypeMap.put(DbType.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,24 +34,24 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
this.closeQuote = "\"";
|
||||
|
||||
booleanDbType = Types.INTEGER;
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("number(1) default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1) default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("number", 10));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("number", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("number", 19, 4));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("number", 19, 4));
|
||||
dbTypeMap.put(Types.SMALLINT, new DbType("number", 5));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("number", 3));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("number", 38));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("number", 19, 4));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("number", 19, 4));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("number", 5));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 38));
|
||||
|
||||
dbTypeMap.put(Types.VARCHAR, new DbType("varchar2", 255));
|
||||
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255));
|
||||
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("blob"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("clob"));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("raw", 255));
|
||||
dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("clob"));
|
||||
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("raw", 255));
|
||||
dbTypeMap.put(DbType.BINARY, new DbPlatformType("raw", 255));
|
||||
|
||||
dbTypeMap.put(Types.TIME, new DbType("timestamp"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("timestamp"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,35 +41,38 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
DbType dbTypeText = new DbType("text");
|
||||
DbType dbBytea = new DbType("bytea", false);
|
||||
DbPlatformType dbTypeText = new DbPlatformType("text");
|
||||
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
|
||||
|
||||
dbTypeMap.put(DbType.HSTORE, new DbType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbType("jsonb", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("timestamptz"));
|
||||
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 38));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("timestamptz"));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, dbBytea);
|
||||
dbTypeMap.put(Types.VARBINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.BINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.VARBINARY, dbBytea);
|
||||
|
||||
dbTypeMap.put(Types.BLOB, dbBytea);
|
||||
dbTypeMap.put(Types.CLOB, dbTypeText);
|
||||
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
|
||||
dbTypeMap.put(DbType.BLOB, dbBytea);
|
||||
dbTypeMap.put(DbType.CLOB, dbTypeText);
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Properties properties) {
|
||||
super.configure(properties);
|
||||
String tsType = properties.getProperty("ebean.postgres.timestamp");
|
||||
if (tsType != null) {
|
||||
// set timestamp type to "timestamp" without time zone
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
|
||||
public void configure(ServerConfig serverConfig) {
|
||||
super.configure(serverConfig);
|
||||
Properties properties = serverConfig.getProperties();
|
||||
if (properties != null) {
|
||||
String tsType = properties.getProperty("ebean.postgres.timestamp");
|
||||
if (tsType != null) {
|
||||
// set timestamp type to "timestamp" without time zone
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType(tsType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
|
||||
dbTypeMap.put(Types.BIT, new DbType("int default 0"));
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("int default 0"));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("integer"));
|
||||
dbTypeMap.put(Types.SMALLINT, new DbType("integer"));
|
||||
dbTypeMap.put(DbType.BIT, new DbPlatformType("int default 0"));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int default 0"));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("integer"));
|
||||
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("integer"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Sybase SQL Anywhere specific platform.
|
||||
* <p>
|
||||
@@ -23,17 +21,17 @@ public class SqlAnywherePlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("numeric", 19));
|
||||
dbTypeMap.put(Types.REAL, new DbType("float(16)"));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float(32)"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("numeric", 28));
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("binary(4500)"));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("long varchar"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("long binary"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("long varchar"));
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("binary(4500)"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("long varchar"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("long binary"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("long varchar"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DB2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
@@ -139,7 +139,7 @@ public class DbMigration {
|
||||
* If not set this defaults to the platform of the default server.
|
||||
* </p>
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
public void setPlatform(Platform platform) {
|
||||
setPlatform(getPlatform(platform));
|
||||
}
|
||||
|
||||
@@ -163,10 +163,7 @@ public class DbMigration {
|
||||
* from the migration (e.g. generate migration sql for MySql, Postgres and Oracle).
|
||||
* </p>
|
||||
*/
|
||||
public void addPlatform(DbPlatformName platform, String prefix) {
|
||||
if (!prefix.endsWith("-")) {
|
||||
prefix += "-";
|
||||
}
|
||||
public void addPlatform(Platform platform, String prefix) {
|
||||
platforms.add(new Pair(getPlatform(platform), prefix));
|
||||
}
|
||||
|
||||
@@ -204,13 +201,20 @@ public class DbMigration {
|
||||
|
||||
// use this flag to stop other plugins like full DDL generation
|
||||
if (!online) {
|
||||
DbOffline.setRunningMigration();
|
||||
DbOffline.setGenerateMigration();
|
||||
if (databasePlatform == null && !platforms.isEmpty()) {
|
||||
// for multiple platform generation set the general platform
|
||||
// to H2 so that it runs offline without DB connection
|
||||
setPlatform(platforms.get(0).platform);
|
||||
}
|
||||
}
|
||||
setDefaults();
|
||||
try {
|
||||
Request request = createRequest();
|
||||
|
||||
generateExtraDdl(request);
|
||||
if (platforms.isEmpty()) {
|
||||
generateExtraDdl(request.migrationDir, databasePlatform);
|
||||
}
|
||||
|
||||
String pendingVersion = generatePendingDrop();
|
||||
if (pendingVersion != null) {
|
||||
@@ -234,15 +238,15 @@ public class DbMigration {
|
||||
* migration runner.
|
||||
* </p>
|
||||
*/
|
||||
private void generateExtraDdl(Request request) throws IOException {
|
||||
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
|
||||
|
||||
if (databasePlatform != null) {
|
||||
if (dbPlatform != null) {
|
||||
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
|
||||
if (extraDdl != null) {
|
||||
List<DdlScript> ddlScript = extraDdl.getDdlScript();
|
||||
for (DdlScript script : ddlScript) {
|
||||
if (ExtraDdlXmlReader.matchPlatform(databasePlatform.getName(), script.getPlatforms())) {
|
||||
writeExtraDdl(request, script);
|
||||
if (ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
|
||||
writeExtraDdl(migrationDir, script);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,13 +256,13 @@ public class DbMigration {
|
||||
/**
|
||||
* Write (or override) the "repeatable" migration script.
|
||||
*/
|
||||
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
|
||||
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
|
||||
|
||||
String fullName = repeatableMigrationName(script.getName());
|
||||
|
||||
logger.info("writing repeatable script {}", fullName);
|
||||
|
||||
File file = new File(request.migrationDir, fullName);
|
||||
File file = new File(migrationDir, fullName);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(script.getValue());
|
||||
writer.flush();
|
||||
@@ -363,14 +367,16 @@ public class DbMigration {
|
||||
logger.warn("migration already exists, not generating DDL");
|
||||
|
||||
} else {
|
||||
if (databasePlatform != null) {
|
||||
if (!platforms.isEmpty()) {
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
|
||||
} else if (databasePlatform != null) {
|
||||
// writer needs the current model to provide table/column details for
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
|
||||
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
|
||||
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
|
||||
}
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +432,10 @@ public class DbMigration {
|
||||
for (Pair pair : platforms) {
|
||||
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
PlatformDdlWriter platformWriter = createDdlWriter(pair);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, writePath, fullVersion);
|
||||
File subPath = platformWriter.subPath(writePath, pair.prefix);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
|
||||
|
||||
generateExtraDdl(subPath, pair.platform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +515,7 @@ public class DbMigration {
|
||||
/**
|
||||
* Return the DatabasePlatform given the platform key.
|
||||
*/
|
||||
protected DatabasePlatform getPlatform(DbPlatformName platform) {
|
||||
protected DatabasePlatform getPlatform(Platform platform) {
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2Platform();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.Platform;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -14,12 +14,12 @@ public class DbOffline {
|
||||
|
||||
private static final String KEY = "ebean.dboffline";
|
||||
|
||||
private static boolean runningMigration;
|
||||
private static boolean generateMigration;
|
||||
|
||||
/**
|
||||
* Set the platform to use when creating the next EbeanServer instance.
|
||||
*/
|
||||
public static void setPlatform(DbPlatformName dbPlatform) {
|
||||
public static void setPlatform(Platform dbPlatform) {
|
||||
System.setProperty(KEY, dbPlatform.name());
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class DbOffline {
|
||||
* Bring up the next EbeanServer instance using the H2 platform.
|
||||
*/
|
||||
public static void asH2() {
|
||||
setPlatform(DbPlatformName.H2);
|
||||
setPlatform(Platform.H2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,23 +55,23 @@ public class DbOffline {
|
||||
* Return true if the migration is running. This typically means don't run the
|
||||
* plugins like full DDL generation.
|
||||
*/
|
||||
public static boolean isRunningMigration() {
|
||||
return runningMigration;
|
||||
public static boolean isGenerateMigration() {
|
||||
return generateMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the migration is running is order to stop other plugins
|
||||
* like the full DDL generation from executing.
|
||||
*/
|
||||
public static void setRunningMigration() {
|
||||
runningMigration = true;
|
||||
public static void setGenerateMigration() {
|
||||
generateMigration = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the offline platform and runningMigration flag.
|
||||
*/
|
||||
public static void reset() {
|
||||
runningMigration = false;
|
||||
generateMigration = false;
|
||||
System.clearProperty(KEY);
|
||||
logger.debug("reset");
|
||||
}
|
||||
|
||||
@@ -96,7 +96,13 @@ public class DdlGenerator {
|
||||
Transaction transaction = server.createTransaction();
|
||||
Connection connection = transaction.getConnection();
|
||||
try {
|
||||
if (expectErrors) {
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
int count = runner.runAll(content, connection);
|
||||
if (expectErrors) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
transaction.commit();
|
||||
return count;
|
||||
|
||||
|
||||
@@ -583,6 +583,12 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
for (Column column : columns) {
|
||||
if (hasValue(column.getReferences())) {
|
||||
writeForeignKey(writer, tableName, column);
|
||||
}
|
||||
}
|
||||
|
||||
// add a bit of whitespace
|
||||
writer.apply().end();
|
||||
}
|
||||
@@ -831,9 +837,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable) throws IOException {
|
||||
|
||||
String convertedType = platformDdl.convert(column.getType(), false);
|
||||
buffer.append("alter table ").append(tableName)
|
||||
.append(" add column ").append(column.getName())
|
||||
.append(" ").append(column.getType());
|
||||
.append(" ").append(convertedType);
|
||||
|
||||
if (!onHistoryTable) {
|
||||
if (isTrue(column.isNotnull())) {
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.util.List;
|
||||
*/
|
||||
public class PlatformDdl {
|
||||
|
||||
protected final DatabasePlatform platform;
|
||||
|
||||
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
|
||||
|
||||
/**
|
||||
@@ -98,6 +100,7 @@ public class PlatformDdl {
|
||||
protected final DbDefaultValue dbDefaultValue;
|
||||
|
||||
public PlatformDdl(DatabasePlatform platform) {
|
||||
this.platform = platform;
|
||||
this.dbIdentity = platform.getDbIdentity();
|
||||
this.dbDefaultValue = platform.getDbDefaultValue();
|
||||
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform.util;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
|
||||
/**
|
||||
* Converts a logical column definition into platform specific one.
|
||||
@@ -10,12 +10,12 @@ import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
*/
|
||||
public class PlatformTypeConverter {
|
||||
|
||||
protected final DbTypeMap platformTypes;
|
||||
protected final DbPlatformTypeMapping platformTypes;
|
||||
|
||||
/**
|
||||
* Construct with the platform specific types.
|
||||
*/
|
||||
public PlatformTypeConverter(DbTypeMap platformTypes) {
|
||||
public PlatformTypeConverter(DbPlatformTypeMapping platformTypes) {
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PlatformTypeConverter {
|
||||
String suffix = close + 1 < columnDefinition.length() ? columnDefinition.substring(close + 1) : "";
|
||||
String type = columnDefinition.substring(0, open);
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(type, true);
|
||||
DbPlatformType dbType = platformTypes.lookup(type, true);
|
||||
int comma = columnDefinition.indexOf(',', open);
|
||||
if (comma > -1) {
|
||||
// scale and precision - decimal(10,4)
|
||||
@@ -73,7 +73,7 @@ public class PlatformTypeConverter {
|
||||
protected String convertNoScale(String columnDefinition) {
|
||||
|
||||
try {
|
||||
DbType dbType = platformTypes.lookup(columnDefinition, false);
|
||||
DbPlatformType dbType = platformTypes.lookup(columnDefinition, false);
|
||||
return dbType.renderType(0, 0);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reads EbeanServer bean descriptors to build the current model.
|
||||
@@ -24,6 +23,8 @@ public class CurrentModel {
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
private final boolean platformTypes;
|
||||
|
||||
private ModelContainer model;
|
||||
|
||||
private ChangeSet changeSet;
|
||||
@@ -31,32 +32,31 @@ public class CurrentModel {
|
||||
private DdlWrite write;
|
||||
|
||||
/**
|
||||
* Construct with a given EbeanServer instance.
|
||||
* Construct with a given EbeanServer instance for DDL create all generation, not migration.
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server) {
|
||||
this(server, server.getServerConfig().getConstraintNaming());
|
||||
this(server, server.getServerConfig().getConstraintNaming(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
|
||||
* <p>
|
||||
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
|
||||
* the platform specific handling on
|
||||
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
|
||||
* the platform specific handling on
|
||||
* </p>
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
|
||||
this(server, constraintNaming, false);
|
||||
}
|
||||
|
||||
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
|
||||
this.server = server;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = maxLength(server, constraintNaming);
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
|
||||
this.server = server;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
|
||||
}
|
||||
|
||||
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
|
||||
if (naming.getMaxLength() != null) {
|
||||
return naming.getMaxLength();
|
||||
@@ -73,7 +73,7 @@ public class CurrentModel {
|
||||
if (model == null) {
|
||||
model = new ModelContainer();
|
||||
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
|
||||
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
|
||||
VisitAllUsing visit = new VisitAllUsing(visitor, server);
|
||||
visit.visitAllBeans();
|
||||
|
||||
@@ -104,7 +104,7 @@ public class MTable {
|
||||
/**
|
||||
* Compound unique constraints.
|
||||
*/
|
||||
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
|
||||
private List<MCompoundUniqueConstraint> uniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
|
||||
|
||||
/**
|
||||
* Compound foreign keys.
|
||||
@@ -216,7 +216,7 @@ public class MTable {
|
||||
createTable.getForeignKey().add(compoundKey.createForeignKey());
|
||||
}
|
||||
|
||||
for (MCompoundUniqueConstraint constraint : compoundUniqueConstraints) {
|
||||
for (MCompoundUniqueConstraint constraint : uniqueConstraints) {
|
||||
UniqueConstraint uq = new UniqueConstraint();
|
||||
uq.setName(constraint.getName());
|
||||
String[] columns = constraint.getColumns();
|
||||
@@ -270,17 +270,15 @@ public class MTable {
|
||||
}
|
||||
|
||||
// compare existing columns (look for dropped columns)
|
||||
int columnPosition = 0;
|
||||
for (MColumn existingColumn : allColumns()) {
|
||||
MColumn newColumn = newColumnMap.get(existingColumn.getName());
|
||||
if (newColumn == null) {
|
||||
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
|
||||
diffDropColumn(modelDiff, existingColumn);
|
||||
} else if (newColumn.isDraftOnly() && !draft) {
|
||||
// effectively a drop column (draft only column on a non-draft table)
|
||||
logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name);
|
||||
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
|
||||
diffDropColumn(modelDiff, existingColumn);
|
||||
}
|
||||
columnPosition++;
|
||||
}
|
||||
|
||||
if (addColumn != null) {
|
||||
@@ -404,8 +402,8 @@ public class MTable {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
|
||||
return compoundUniqueConstraints;
|
||||
public List<MCompoundUniqueConstraint> getUniqueConstraints() {
|
||||
return uniqueConstraints;
|
||||
}
|
||||
|
||||
public List<MCompoundForeignKey> getCompoundKeys() {
|
||||
@@ -476,21 +474,21 @@ public class MTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
|
||||
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
|
||||
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
|
||||
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a compound unique constraint.
|
||||
* Add a unique constraint.
|
||||
*/
|
||||
public void addCompoundUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
|
||||
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
|
||||
String[] cols = new String[columns.size()];
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
cols[i] = columns.get(i).getName();
|
||||
}
|
||||
addCompoundUniqueConstraint(cols, oneToOne, constraintName);
|
||||
addUniqueConstraint(cols, oneToOne, constraintName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -540,7 +538,7 @@ public class MTable {
|
||||
/**
|
||||
* Add a 'drop column' to the diff.
|
||||
*/
|
||||
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) {
|
||||
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
|
||||
|
||||
DropColumn dropColumn = new DropColumn();
|
||||
dropColumn.setTableName(name);
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@@ -21,6 +23,8 @@ import java.util.List;
|
||||
*/
|
||||
public class PlatformDdlWriter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlatformDdlWriter.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DatabasePlatform platform;
|
||||
@@ -67,7 +71,7 @@ public class PlatformDdlWriter {
|
||||
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
|
||||
|
||||
if (!write.isApplyEmpty()) {
|
||||
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
|
||||
FileWriter applyWriter = createWriter(resourcePath, fullVersion, config.getApplySuffix());
|
||||
try {
|
||||
writeApplyDdl(applyWriter, write);
|
||||
applyWriter.flush();
|
||||
@@ -77,28 +81,12 @@ public class PlatformDdlWriter {
|
||||
}
|
||||
}
|
||||
|
||||
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
|
||||
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
|
||||
|
||||
String fileName = fullVersion;
|
||||
if (!platformPrefix.isEmpty()) {
|
||||
fileName += "-"+platformPrefix;
|
||||
}
|
||||
if (subPath != null && !subPath.isEmpty()) {
|
||||
path = subPath(path, subPath);
|
||||
}
|
||||
fileName += suffix;
|
||||
File applyFile = new File(path, fileName);
|
||||
File applyFile = new File(path, fullVersion + suffix);
|
||||
return new FileWriter(applyFile);
|
||||
}
|
||||
|
||||
protected File subPath(File path, String suffix) {
|
||||
File subPath = new File(path, suffix);
|
||||
if (!subPath.exists()) {
|
||||
subPath.mkdirs();
|
||||
}
|
||||
return subPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the 'Apply' DDL buffers to the writer.
|
||||
*/
|
||||
@@ -127,4 +115,17 @@ public class PlatformDdlWriter {
|
||||
return platform.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a sub directory (for multi-platform ddl generation).
|
||||
*/
|
||||
public File subPath(File path, String suffix) {
|
||||
File subPath = new File(path, suffix);
|
||||
if (!subPath.exists()) {
|
||||
if (!subPath.mkdirs()) {
|
||||
logger.error("failed to create directories for " + subPath.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
return subPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration.model.build;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.dbmigration.migration.IdentityType;
|
||||
import com.avaje.ebean.dbmigration.model.MColumn;
|
||||
@@ -52,7 +52,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
|
||||
if (inheritInfo != null && inheritInfo.isRoot()) {
|
||||
// add the discriminator column
|
||||
String discColumn = inheritInfo.getDiscriminatorColumn();
|
||||
DbType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
|
||||
DbPlatformType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
|
||||
String discDbType = dbType.renderType(inheritInfo.getDiscriminatorLength(), 0);
|
||||
|
||||
table.addColumn(new MColumn(discColumn, discDbType, true));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebean.dbmigration.model.build;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebean.config.dbplatform.DbTypeMap;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformType;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformTypeMapping;
|
||||
import com.avaje.ebean.dbmigration.model.MColumn;
|
||||
import com.avaje.ebean.dbmigration.model.MTable;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
@@ -21,7 +21,7 @@ public class ModelBuildContext {
|
||||
* Use platform agnostic logical types. These types are converted to
|
||||
* platform specific types in the DDL generation.
|
||||
*/
|
||||
private final DbTypeMap dbTypeMap = DbTypeMap.logicalTypes();
|
||||
private final DbPlatformTypeMapping dbTypeMap = DbPlatformTypeMapping.logicalTypes();
|
||||
|
||||
private final ModelContainer model;
|
||||
|
||||
@@ -29,10 +29,13 @@ public class ModelBuildContext {
|
||||
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
|
||||
private final boolean platformTypes;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
|
||||
this.model = model;
|
||||
this.constraintNaming = naming;
|
||||
this.maxLength = maxLength;
|
||||
this.platformTypes = platformTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +106,7 @@ public class ModelBuildContext {
|
||||
* Return the map used to determine the DB specific type
|
||||
* for a given bean property.
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
public DbPlatformTypeMapping getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
@@ -112,14 +115,14 @@ public class ModelBuildContext {
|
||||
* Render the DB type for this property given the strict mode.
|
||||
*/
|
||||
public String getColumnDefn(BeanProperty p, boolean strict) {
|
||||
DbType dbType = getDbType(p);
|
||||
DbPlatformType dbType = getDbType(p);
|
||||
if (dbType == null) {
|
||||
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
|
||||
}
|
||||
return p.renderDbType(dbType, strict);
|
||||
}
|
||||
|
||||
private DbType getDbType(BeanProperty p) {
|
||||
private DbPlatformType getDbType(BeanProperty p) {
|
||||
|
||||
if (p.isDbEncrypted()) {
|
||||
return dbTypeMap.get(p.getDbEncryptedType());
|
||||
@@ -132,7 +135,7 @@ public class ModelBuildContext {
|
||||
}
|
||||
|
||||
// can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar)
|
||||
int dbType = p.getDbType();
|
||||
int dbType = p.getDbType(platformTypes);
|
||||
if (dbType == 0) {
|
||||
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
|
||||
}
|
||||
|
||||
+12
-21
@@ -10,7 +10,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
|
||||
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
@@ -45,30 +45,30 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
this.ctx = ctx;
|
||||
this.table = table;
|
||||
this.beanDescriptor = beanDescriptor;
|
||||
addCompoundUniqueConstraint(beanDescriptor.getCompoundUniqueConstraints());
|
||||
addIndexes(beanDescriptor.getIndexDefinitions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add unique constraints defined via JPA UniqueConstraint annotations.
|
||||
*/
|
||||
private void addCompoundUniqueConstraint(CompoundUniqueConstraint[] constraints) {
|
||||
private void addIndexes(IndexDefinition[] indexes) {
|
||||
|
||||
if (constraints != null) {
|
||||
for (int i = 0; i < constraints.length; i++) {
|
||||
CompoundUniqueConstraint constraint = constraints[i];
|
||||
String[] columns = constraint.getColumns();
|
||||
if (indexes != null) {
|
||||
for (int i = 0; i < indexes.length; i++) {
|
||||
IndexDefinition index = indexes[i];
|
||||
String[] columns = index.getColumns();
|
||||
indexSet.add(columns);
|
||||
|
||||
if (constraint.isUnique()) {
|
||||
String uqName = constraint.getName();
|
||||
if (index.isUnique()) {
|
||||
String uqName = index.getName();
|
||||
if (uqName == null || uqName.trim().isEmpty()) {
|
||||
uqName = determineUniqueConstraintName(columns);
|
||||
}
|
||||
table.addCompoundUniqueConstraint(columns, false, uqName);
|
||||
table.addUniqueConstraint(columns, false, uqName);
|
||||
|
||||
} else {
|
||||
// 'just' an index (not a unique constraint)
|
||||
String idxName = constraint.getName();
|
||||
String idxName = index.getName();
|
||||
if (idxName == null || idxName.trim().isEmpty()) {
|
||||
idxName = determineIndexName(columns);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
|
||||
} else {
|
||||
String uqName = determineUniqueConstraintName(p.getName());
|
||||
table.addCompoundUniqueConstraint(modelColumns, true, uqName);
|
||||
table.addUniqueConstraint(modelColumns, true, uqName);
|
||||
indexSetAdd(modelColumns);
|
||||
}
|
||||
}
|
||||
@@ -260,15 +260,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
|
||||
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
|
||||
}
|
||||
|
||||
String indexName = p.getIndexName();
|
||||
if (indexName != null) {
|
||||
// single column non-unique index
|
||||
if (indexName.trim().isEmpty()) {
|
||||
indexName = determineIndexName(col.getName());
|
||||
}
|
||||
ctx.addIndex(indexName, table.getName(), p.getDbColumn());
|
||||
}
|
||||
|
||||
lastColumn = col;
|
||||
table.addColumn(col);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used to enhance or override the default bean persistence mechanism.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
/**
|
||||
* Fired after a bean is constructed, but not yet loaded from database.
|
||||
* <p>
|
||||
* Note: You MUST NOT set any default values, as in a following step,
|
||||
* properties will get unload. Use {@link BeanPostLoad} instead.
|
||||
*
|
||||
* it's intended to do some dependency-injection here.
|
||||
* If you plan to use this feature you should use {@link EbeanServer#createEntityBean(Class)}
|
||||
* to create new beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanPostConstructListener {
|
||||
|
||||
/**
|
||||
* Return true if this BeanPostConstructListener instance should be registered
|
||||
* for post construct on this entity type.
|
||||
*/
|
||||
boolean isRegisterFor(Class<?> cls);
|
||||
|
||||
/**
|
||||
* Called immediately after construction. Perform DI here.
|
||||
*/
|
||||
void autowire(Object bean);
|
||||
|
||||
/**
|
||||
* Called after every @PostConstruct annotated method of the bean is executed
|
||||
*/
|
||||
void postConstruct(Object bean);
|
||||
|
||||
/**
|
||||
* Called after {@link EbeanServer#createEntityBean(Class)}. Only for new beans.
|
||||
* intended to set default values here.
|
||||
*/
|
||||
void postCreate(Object bean);
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
|
||||
/**
|
||||
* Used to get notified about commit or rollback of a transaction
|
||||
*/
|
||||
public interface TransactionEventListener {
|
||||
/**
|
||||
* Called after the transaction has been committed
|
||||
*/
|
||||
void postTransactionCommit(Transaction tx);
|
||||
|
||||
/**
|
||||
* Called after the transaction has been rolled back
|
||||
*/
|
||||
void postTransactionRollback(Transaction tx, Throwable cause);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
|
||||
/**
|
||||
* A no operation implementation of TransactionEventListener. Objects extending
|
||||
* this need to only override the methods they want to.
|
||||
*/
|
||||
public abstract class TransactionEventListenerAdapter implements TransactionEventListener {
|
||||
|
||||
public void postTransactionCommit(Transaction tx) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
public void postTransactionRollback(Transaction tx, Throwable cause) {
|
||||
// do nothing by default
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class BeanChange {
|
||||
* Set the bean id (for JSON tools).
|
||||
*/
|
||||
public void setId(Object id) {
|
||||
this.id = this.id;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,9 +12,12 @@ public class CamelCaseHelper {
|
||||
*/
|
||||
public static String toCamelFromUnderscore(String underscore) {
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
String[] vals = underscore.split("_");
|
||||
if (vals.length == 1) {
|
||||
return underscore;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
String lower = vals[i].toLowerCase();
|
||||
if (i > 0) {
|
||||
|
||||
@@ -398,7 +398,7 @@ public class StringHelper {
|
||||
int additionalSize, int startPos, int endPos) {
|
||||
|
||||
if (source == null) {
|
||||
return source;
|
||||
return null;
|
||||
}
|
||||
|
||||
char match0 = match.charAt(0);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
public final class DerivedRelationshipData {
|
||||
|
||||
private final Object assocBean;
|
||||
private final String logicalName;
|
||||
private final Object bean;
|
||||
|
||||
public DerivedRelationshipData(Object assocBean, String logicalName, Object bean) {
|
||||
this.assocBean = assocBean;
|
||||
this.logicalName = logicalName;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
public Object getAssocBean() {
|
||||
return assocBean;
|
||||
}
|
||||
|
||||
public String getLogicalName() {
|
||||
return logicalName;
|
||||
}
|
||||
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -169,8 +169,13 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
EntityBeanIntercept ebi = batch.get(i);
|
||||
Object id = desc.getId(ebi.getOwner());
|
||||
if (!loadedIds.contains(id)) {
|
||||
logger.info("Lazy loading unsuccessful for type:" + desc.getName() + " id:" + id + " - expecting when bean has been deleted");
|
||||
ebi.setLazyLoadFailure(id);
|
||||
if (desc.isSoftDelete()) {
|
||||
// assume this is logically deleted (hence not found)
|
||||
desc.setSoftDeleteValue(ebi.getOwner());
|
||||
} else {
|
||||
logger.info("Lazy loading unsuccessful for type:" + desc.getName() + " id:" + id + " - expecting when bean has been deleted");
|
||||
ebi.setLazyLoadFailure(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,15 +132,11 @@ public class ManyWhereJoins implements Serializable {
|
||||
formulaProperties.append(propertyName);
|
||||
}
|
||||
|
||||
public boolean isHasMany() {
|
||||
return formulaWithJoin || !joins.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the findRowCount query just needs the id property in the select clause.
|
||||
* Return true if the query select includes a formula with join.
|
||||
*/
|
||||
public boolean isSelectId() {
|
||||
return !formulaWithJoin;
|
||||
public boolean isFormulaWithJoin() {
|
||||
return formulaWithJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -181,6 +181,15 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the underlying transaction as rollback only.
|
||||
*/
|
||||
public void setRollbackOnly() {
|
||||
if (transaction != null) {
|
||||
transaction.setRollbackOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Exception was caught and may or may not cause a rollback to occur.
|
||||
* Returns the exception and this should be thrown by the calling code.
|
||||
|
||||
@@ -8,13 +8,13 @@ import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper of a ScopeTrans request and it's underlying transaction.
|
||||
@@ -29,9 +29,13 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
|
||||
public ScopedTransaction(ScopeTrans scopeTrans) {
|
||||
this.scopeTrans = scopeTrans;
|
||||
this.transaction =scopeTrans.getTransaction();
|
||||
this.transaction = scopeTrans.getTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitAndContinue() throws RollbackException {
|
||||
transaction.commitAndContinue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws RollbackException {
|
||||
@@ -49,6 +53,21 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
scopeTrans.rollback(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollbackIfActive() {
|
||||
transaction.rollbackIfActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
scopeTrans.setRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRollbackOnly() {
|
||||
return transaction.isRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() throws PersistenceException {
|
||||
try {
|
||||
@@ -126,13 +145,8 @@ public class ScopedTransaction implements SpiTransaction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean) {
|
||||
transaction.registerDerivedRelationship(assocBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean) {
|
||||
return transaction.getDerivedRelationship(bean);
|
||||
public void registerDeferred(PersistDeferredRelationship derived) {
|
||||
transaction.registerDeferred(derived);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -145,7 +145,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
* the query has finished (if executing in a background thread).
|
||||
* </p>
|
||||
*/
|
||||
<T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
|
||||
<A> List<A> findIdsWithCopy(Query<?> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the findRowCount query but without copying the query.
|
||||
|
||||
@@ -13,7 +13,12 @@ import java.io.IOException;
|
||||
*/
|
||||
public interface SpiExpression extends Expression {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Simplify nested expressions if possible.
|
||||
*/
|
||||
void simplify();
|
||||
|
||||
/**
|
||||
* Write the expression as an elastic search expression.
|
||||
*/
|
||||
void writeDocQuery(DocQueryContext context) throws IOException;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
public interface SpiNamedParam {
|
||||
|
||||
Object getValue();
|
||||
}
|
||||
@@ -78,6 +78,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
ID_LIST,
|
||||
|
||||
/**
|
||||
* Find single attribute.
|
||||
*/
|
||||
ATTRIBUTE,
|
||||
|
||||
/**
|
||||
* Find rowCount.
|
||||
*/
|
||||
@@ -222,6 +227,16 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
Timestamp getAsOf();
|
||||
|
||||
/**
|
||||
* Return true if the base table is using history.
|
||||
*/
|
||||
boolean isAsOfBaseTable();
|
||||
|
||||
/**
|
||||
* Set when the base table is using history.
|
||||
*/
|
||||
void setAsOfBaseTable();
|
||||
|
||||
/**
|
||||
* Increment the counter of tables used in 'As Of' query.
|
||||
*/
|
||||
@@ -236,21 +251,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
|
||||
List<String> getSoftDeletePredicates();
|
||||
|
||||
/**
|
||||
* Set the list of Id's that is being populated.
|
||||
* <p>
|
||||
* This is a mutating list of id's and we are setting this so that other
|
||||
* threads have access to the id's before the id query has finished.
|
||||
* </p>
|
||||
*/
|
||||
void setIdList(List<Object> ids);
|
||||
|
||||
/**
|
||||
* Return the list of Id's that is currently being fetched by a background
|
||||
* thread.
|
||||
*/
|
||||
List<Object> getIdList();
|
||||
|
||||
/**
|
||||
* Return a copy of the query.
|
||||
*/
|
||||
@@ -296,6 +296,16 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
void setLoadDescription(String loadMode, String loadDescription);
|
||||
|
||||
/**
|
||||
* Check that the named parameters have had their values set.
|
||||
*/
|
||||
void checkNamedParameters();
|
||||
|
||||
/**
|
||||
* Create a named parameter placeholder.
|
||||
*/
|
||||
SpiNamedParam createNamedParameter(String parameterName);
|
||||
|
||||
/**
|
||||
* Return the joins required to support predicates on the many properties.
|
||||
*/
|
||||
@@ -321,6 +331,24 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
void setSelectId();
|
||||
|
||||
/**
|
||||
* Mark the query as selecting a single attribute.
|
||||
*/
|
||||
void setSingleAttribute();
|
||||
|
||||
/**
|
||||
* Return true if this is singleAttribute query.
|
||||
*/
|
||||
boolean isSingleAttribute();
|
||||
|
||||
/**
|
||||
* Return true if the query should include the Id property.
|
||||
* <p>
|
||||
* distinct and single attribute queries exclude the Id property.
|
||||
* </p>
|
||||
*/
|
||||
boolean isWithId();
|
||||
|
||||
/**
|
||||
* Set a filter to a join path.
|
||||
*/
|
||||
@@ -542,12 +570,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
BindParams getBindParams();
|
||||
|
||||
/**
|
||||
* Get the orm query as a String. Only available if the query was built from
|
||||
* a string.
|
||||
*/
|
||||
String getQuery();
|
||||
|
||||
/**
|
||||
* Replace the query detail. This is used by the AutoTune feature to as a
|
||||
* fast way to set the query properties and joins.
|
||||
@@ -564,6 +586,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
boolean tuneFetchProperties(OrmQueryDetail detail);
|
||||
|
||||
/**
|
||||
* If this is a RawSql based entity set the default RawSql if not set.
|
||||
*/
|
||||
void setDefaultRawSqlIfRequired();
|
||||
|
||||
/**
|
||||
* Set to true if this query has been tuned by autoTune.
|
||||
*/
|
||||
@@ -574,9 +601,15 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
OrmQueryDetail getDetail();
|
||||
|
||||
TableJoin getIncludeTableJoin();
|
||||
/**
|
||||
* Return the extra join for a M2M lazy load.
|
||||
*/
|
||||
TableJoin getM2mIncludeJoin();
|
||||
|
||||
void setIncludeTableJoin(TableJoin includeTableJoin);
|
||||
/**
|
||||
* Set the extra join for a M2M lazy load.
|
||||
*/
|
||||
void setM2MIncludeJoin(TableJoin includeTableJoin);
|
||||
|
||||
/**
|
||||
* Return the property used to specify keys for a map.
|
||||
@@ -625,6 +658,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
void setGeneratedSql(String generatedSql);
|
||||
|
||||
/**
|
||||
* Set the JDBC fetchSize buffer hint if not explicitly set.
|
||||
*/
|
||||
void setDefaultFetchBuffer(int fetchSize);
|
||||
|
||||
/**
|
||||
* Return the hint for Statement.setFetchSize().
|
||||
*/
|
||||
@@ -681,4 +719,8 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
OrmUpdateProperties getUpdateProperties();
|
||||
|
||||
/**
|
||||
* Simplify nested expression lists where possible.
|
||||
*/
|
||||
void simplifyExpressions();
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequest;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extends Transaction with additional API required on server.
|
||||
@@ -48,15 +48,9 @@ public interface SpiTransaction extends Transaction {
|
||||
void logSummary(String msg);
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
* Register a "Deferred Relationship" that requires an additional update later.
|
||||
*/
|
||||
void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
void registerDeferred(PersistDeferredRelationship derived);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
@@ -220,6 +214,12 @@ public interface SpiTransaction extends Transaction {
|
||||
*/
|
||||
Connection getInternalConnection();
|
||||
|
||||
/**
|
||||
* Rollback if the transaction is active. This provides an internal
|
||||
* mechanism for rollback failures occur on commit().
|
||||
*/
|
||||
void rollbackIfActive();
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
|
||||
+3
-5
@@ -19,8 +19,7 @@ public class AutoTuneXmlReader {
|
||||
/**
|
||||
* Read and return a Profiling from an xml file.
|
||||
*/
|
||||
public Autotune read(File file) {
|
||||
|
||||
public static Autotune read(File file) {
|
||||
try {
|
||||
return readFile(file);
|
||||
} catch (IOException e) {
|
||||
@@ -28,7 +27,7 @@ public class AutoTuneXmlReader {
|
||||
}
|
||||
}
|
||||
|
||||
protected Autotune readFile(File file) throws IOException {
|
||||
protected static Autotune readFile(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
return new Autotune();
|
||||
}
|
||||
@@ -43,8 +42,7 @@ public class AutoTuneXmlReader {
|
||||
/**
|
||||
* Read and return a Profiling from an xml document.
|
||||
*/
|
||||
public Autotune read(InputStream is) {
|
||||
|
||||
public static Autotune read(InputStream is) {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(Autotune.class);
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
|
||||
+16
-8
@@ -12,6 +12,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -101,19 +102,26 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
*/
|
||||
private void loadTuningFile() {
|
||||
File file = new File(tuningFile);
|
||||
if (!file.exists()) {
|
||||
logger.warn("AutoTune file {} not found - no initial automatic query tuning", file.getAbsolutePath());
|
||||
|
||||
if (file.exists()) {
|
||||
loadAutoTuneProfiling(AutoTuneXmlReader.read(file));
|
||||
} else {
|
||||
AutoTuneXmlReader reader = new AutoTuneXmlReader();
|
||||
Autotune profiling = reader.read(file);
|
||||
logger.info("AutoTune loading {} tuning entries", profiling.getOrigin().size());
|
||||
for (Origin origin : profiling.getOrigin()) {
|
||||
queryTuner.put(origin);
|
||||
// look for autotune as a resource
|
||||
InputStream stream = getClass().getResourceAsStream("/" + tuningFile);
|
||||
if (stream != null) {
|
||||
loadAutoTuneProfiling(AutoTuneXmlReader.read(stream));
|
||||
} else {
|
||||
logger.warn("AutoTune file {} not found - no initial automatic query tuning", tuningFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAutoTuneProfiling(Autotune profiling) {
|
||||
logger.info("AutoTune loading {} tuning entries", profiling.getOrigin().size());
|
||||
for (Origin origin : profiling.getOrigin()) {
|
||||
queryTuner.put(origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect profiling, check for new/diff to existing tuning and apply changes.
|
||||
*/
|
||||
|
||||
+1
-2
@@ -45,9 +45,8 @@ public class ProfileOriginNodeUsage {
|
||||
if (path != null) {
|
||||
ElPropertyValue elGetValue = rootDesc.getElGetValue(path);
|
||||
if (elGetValue == null) {
|
||||
desc = null;
|
||||
logger.warn("AutoTune: Can't find join for path[" + path + "] for " + rootDesc.getName());
|
||||
|
||||
return;
|
||||
} else {
|
||||
BeanProperty beanProperty = elGetValue.getBeanProperty();
|
||||
if (beanProperty instanceof BeanPropertyAssoc<?>) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.cache.ServerCacheStatistics;
|
||||
|
||||
+2
-8
@@ -5,6 +5,7 @@ import com.avaje.ebean.annotation.ChangeLogInsertMode;
|
||||
import com.avaje.ebean.event.BeanPersistRequest;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogFilter;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.AnnotationBase;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -52,14 +53,7 @@ public class DefaultChangeLogRegister implements ChangeLogRegister {
|
||||
* Find and return the ChangeLog annotation in the inheritance hierarchy.
|
||||
*/
|
||||
private ChangeLog getChangeLog(Class<?> beanType) {
|
||||
ChangeLog changeLog = beanType.getAnnotation(ChangeLog.class);
|
||||
if (changeLog != null) {
|
||||
return changeLog;
|
||||
}
|
||||
if (Object.class.equals(beanType.getSuperclass())) {
|
||||
return null;
|
||||
}
|
||||
return getChangeLog(beanType.getSuperclass());
|
||||
return AnnotationBase.findAnnotation(beanType, ChangeLog.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -150,6 +150,9 @@ public final class BasicTypeConverter implements Serializable {
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number)value).intValue() == 1;
|
||||
}
|
||||
String s = value.toString();
|
||||
return s.equalsIgnoreCase(dbTrueValue);
|
||||
}
|
||||
|
||||
@@ -68,11 +68,11 @@ public abstract class BeanRequest {
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
try {
|
||||
transaction.rollback();
|
||||
transaction.rollbackIfActive();
|
||||
} catch (Exception e) {
|
||||
// Just log this and carry on. A previous exception has been
|
||||
// thrown and if this rollback throws exception it likely means
|
||||
// that the connection is broken (and the datasource and db will cleanup)
|
||||
// that the connection is broken (and the dataSource and db will cleanup)
|
||||
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,25 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonExecutorService;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
private final DaemonExecutorService pool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param corePoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param maximumPoolSize
|
||||
* the maximum pool size before jobs are queued
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, int maximumPoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(corePoolSize, maximumPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ import java.util.Set;
|
||||
*/
|
||||
public class DefaultBeanState implements BeanState {
|
||||
|
||||
private final EntityBean entityBean;
|
||||
|
||||
private final EntityBeanIntercept intercept;
|
||||
|
||||
public DefaultBeanState(EntityBean entityBean){
|
||||
this.entityBean = entityBean;
|
||||
this.intercept = entityBean._ebean_getIntercept();
|
||||
}
|
||||
private final EntityBean entityBean;
|
||||
|
||||
private final EntityBeanIntercept intercept;
|
||||
|
||||
public DefaultBeanState(EntityBean entityBean) {
|
||||
this.entityBean = entityBean;
|
||||
this.intercept = entityBean._ebean_getIntercept();
|
||||
}
|
||||
|
||||
public void setPropertyLoaded(String propertyName, boolean loaded) {
|
||||
intercept.setPropertyLoaded(propertyName, loaded);
|
||||
@@ -31,52 +31,62 @@ public class DefaultBeanState implements BeanState {
|
||||
return intercept.isReference();
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return intercept.isNew();
|
||||
}
|
||||
|
||||
public boolean isNewOrDirty() {
|
||||
return intercept.isNewOrDirty();
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return intercept.isDirty();
|
||||
}
|
||||
|
||||
public Set<String> getLoadedProps() {
|
||||
return intercept.getLoadedPropertyNames();
|
||||
}
|
||||
|
||||
public Set<String> getChangedProps() {
|
||||
return intercept.getDirtyPropertyNames();
|
||||
public boolean isNew() {
|
||||
return intercept.isNew();
|
||||
}
|
||||
|
||||
public Map<String,ValuePair> getDirtyValues() {
|
||||
|
||||
public boolean isNewOrDirty() {
|
||||
return intercept.isNewOrDirty();
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return intercept.isDirty();
|
||||
}
|
||||
|
||||
public Set<String> getLoadedProps() {
|
||||
return intercept.getLoadedPropertyNames();
|
||||
}
|
||||
|
||||
public Set<String> getChangedProps() {
|
||||
return intercept.getDirtyPropertyNames();
|
||||
}
|
||||
|
||||
public Map<String, ValuePair> getDirtyValues() {
|
||||
return intercept.getDirtyValues();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return intercept.isReadOnly();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly){
|
||||
intercept.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
entityBean.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
entityBean.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void setLoaded() {
|
||||
intercept.setLoaded();
|
||||
}
|
||||
public boolean isReadOnly() {
|
||||
return intercept.isReadOnly();
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
intercept.setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
entityBean.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
entityBean.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void setLoaded() {
|
||||
intercept.setLoaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoading) {
|
||||
intercept.setDisableLazyLoad(disableLazyLoading);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableLazyLoad() {
|
||||
return intercept.isDisableLazyLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForInsert() {
|
||||
intercept.setNew();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,14 +78,10 @@ public class DefaultContainer implements SpiContainer {
|
||||
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig) {
|
||||
|
||||
String namePrefix = "ebean-" + serverConfig.getName();
|
||||
|
||||
int schedulePoolSize = serverConfig.getBackgroundExecutorSchedulePoolSize();
|
||||
int corePoolSize = serverConfig.getBackgroundExecutorCorePoolSize();
|
||||
int maxPoolSize = serverConfig.getBackgroundExecutorMaxPoolSize();
|
||||
int idleSecs = serverConfig.getBackgroundExecutorIdleSecs();
|
||||
int shutdownSecs = serverConfig.getBackgroundExecutorShutdownSecs();
|
||||
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, corePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,22 +118,20 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
// generate and run DDL if required
|
||||
// if there are any other tasks requiring action in their plugins, do them as well
|
||||
if (!DbOffline.isRunningMigration()) {
|
||||
if (!DbOffline.isGenerateMigration()) {
|
||||
server.executePlugins(online);
|
||||
}
|
||||
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
// register the server once it has been created
|
||||
clusterManager.registerServer(server);
|
||||
// initialise prior to registering with clusterManager
|
||||
server.initialise();
|
||||
if (online) {
|
||||
if (clusterManager.isClustering()) {
|
||||
// register the server once it has been created
|
||||
clusterManager.registerServer(server);
|
||||
}
|
||||
}
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
}
|
||||
|
||||
// start any services after registering with clusterManager
|
||||
server.start();
|
||||
DbOffline.reset();
|
||||
return server;
|
||||
}
|
||||
@@ -200,8 +194,8 @@ public class DefaultContainer implements SpiContainer {
|
||||
bootup.addIdGenerators(serverConfig.getIdGenerators());
|
||||
bootup.addPersistControllers(serverConfig.getPersistControllers());
|
||||
bootup.addPostLoaders(serverConfig.getPostLoaders());
|
||||
bootup.addPostConstructListeners(serverConfig.getPostConstructListeners());
|
||||
bootup.addFindControllers(serverConfig.getFindControllers());
|
||||
bootup.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
|
||||
bootup.addPersistListeners(serverConfig.getPersistListeners());
|
||||
bootup.addQueryAdapters(serverConfig.getQueryAdapters());
|
||||
bootup.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
|
||||
@@ -244,7 +238,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
if (dbPlatform == null) {
|
||||
DatabasePlatformFactory factory = new DatabasePlatformFactory();
|
||||
DatabasePlatform db = factory.create(config);
|
||||
db.configure(config.getProperties());
|
||||
db.configure(config);
|
||||
config.setDatabasePlatform(db);
|
||||
logger.info("DatabasePlatform name:" + config.getName() + " platform:" + db.getName());
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.el.ElFilter;
|
||||
import com.avaje.ebeaninternal.server.grammer.EqlParser;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
@@ -70,10 +71,8 @@ import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -524,7 +523,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T createEntityBean(Class<T> type) {
|
||||
BeanDescriptor<T> desc = getBeanDescriptor(type);
|
||||
return (T) desc.createEntityBean();
|
||||
return (T) desc.createEntityBean(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,7 +556,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
InheritInfo inheritInfo = desc.getInheritInfo();
|
||||
if (inheritInfo == null) {
|
||||
return (T)desc.contextRef(pc, null, id);
|
||||
return (T)desc.contextRef(pc, null, false, id);
|
||||
}
|
||||
|
||||
BeanProperty idProp = desc.getIdProperty();
|
||||
@@ -683,6 +682,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
if (txScope == null) {
|
||||
// create a TxScope with default settings
|
||||
txScope = new TxScope();
|
||||
} else {
|
||||
// check for implied batch mode via setting batchSize
|
||||
txScope.checkBatchMode();
|
||||
}
|
||||
|
||||
SpiTransaction suspended = null;
|
||||
@@ -884,6 +886,32 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return createQuery(beanType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
|
||||
if (desc == null) {
|
||||
throw new PersistenceException(beanType.getName() + " is NOT an Entity Bean registered with this server?");
|
||||
}
|
||||
String named = desc.getNamedQuery(namedQuery);
|
||||
if (named != null) {
|
||||
return createQuery(beanType, named);
|
||||
}
|
||||
RawSql rawSql = desc.getNamedRawSql(namedQuery);
|
||||
if (rawSql != null) {
|
||||
DefaultOrmQuery<T> query = createQuery(beanType);
|
||||
query.setRawSql(rawSql);
|
||||
return query;
|
||||
}
|
||||
throw new PersistenceException("No named query called " + namedQuery + " for bean:" + beanType.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Query<T> createQuery(Class<T> beanType, String eql) {
|
||||
DefaultOrmQuery<T> query = createQuery(beanType);
|
||||
EqlParser.parse(eql, query);
|
||||
return query;
|
||||
}
|
||||
|
||||
public <T> DefaultOrmQuery<T> createQuery(Class<T> beanType) {
|
||||
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
|
||||
if (desc == null) {
|
||||
@@ -936,12 +964,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
spiQuery.setType(type);
|
||||
spiQuery.checkNamedParameters();
|
||||
|
||||
return createQueryRequest(spiQuery, t);
|
||||
}
|
||||
|
||||
private <T> SpiOrmQueryRequest<T> createQueryRequest(SpiQuery<T> query, Transaction t) {
|
||||
|
||||
query.setDefaultRawSqlIfRequired();
|
||||
if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) {
|
||||
// use deployment FetchType.LAZY/EAGER annotations
|
||||
// to define the 'default' select clause
|
||||
@@ -1102,30 +1132,52 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public <T> Map<?, T> findMap(Query<T> query, Transaction t) {
|
||||
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
|
||||
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (Map<?, T>) result;
|
||||
return (Map<K, T>) result;
|
||||
}
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (Map<?, T>) request.findMap();
|
||||
return (Map<K, T>) request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> int findRowCount(Query<T> query, Transaction t) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A> List<A> findSingleAttributeList(Query<?> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t);
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (List<A>) result;
|
||||
}
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (List<A>) request.findSingleAttributeList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> int findCount(Query<T> query, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
return findRowCountWithCopy(copy, t);
|
||||
}
|
||||
|
||||
public <T> int findRowCount(Query<T> query, Transaction t) {
|
||||
return findCount(query, t);
|
||||
}
|
||||
|
||||
public <T> int findRowCountWithCopy(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
|
||||
@@ -1138,16 +1190,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> List<Object> findIds(Query<T> query, Transaction t) {
|
||||
public <A> List<A> findIds(Query<?> query, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
|
||||
return findIdsWithCopy(copy, t);
|
||||
return findIdsWithCopy(((SpiQuery<?>) query).copy(), t);
|
||||
}
|
||||
|
||||
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t) {
|
||||
public <A> List<A> findIdsWithCopy(Query<?> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIds();
|
||||
@@ -1181,7 +1231,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
|
||||
public <T> FutureRowCount<T> findFutureCount(Query<T> q, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) q).copy();
|
||||
copy.setFutureFetch(true);
|
||||
@@ -1196,17 +1246,15 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return queryFuture;
|
||||
}
|
||||
|
||||
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
|
||||
return findFutureCount(q, t);
|
||||
}
|
||||
|
||||
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
copy.setFutureFetch(true);
|
||||
|
||||
// this is the list we will put the id's in ... create it now so
|
||||
// it is available for other threads to read while the id query
|
||||
// is still executing (we don't need to wait for it to finish)
|
||||
List<Object> idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
copy.setIdList(idList);
|
||||
|
||||
Transaction newTxn = createTransaction();
|
||||
|
||||
CallableQueryIds<T> call = new CallableQueryIds<T>(this, copy, newTxn);
|
||||
@@ -1254,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return new LimitOffsetPagedList<T>(this, spiQuery);
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIterate();
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.endTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
@@ -137,7 +137,7 @@ public class InternalConfiguration {
|
||||
|
||||
this.dataTimeZone = initDataTimeZone();
|
||||
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
|
||||
this.cQueryEngine = new CQueryEngine(databasePlatform, binder, asOfTableMapping, serverConfig.getAsOfSysPeriod(), draftTableMap);
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,14 +340,14 @@ public class InternalConfiguration {
|
||||
|
||||
boolean localL2 = cacheManager.isLocalL2Caching();
|
||||
if (serverConfig.isExplicitTransactionBeginMode()) {
|
||||
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -21,6 +21,14 @@ public interface OrmQueryEngine {
|
||||
*/
|
||||
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Execute the findVersions query.
|
||||
*/
|
||||
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
@@ -36,7 +44,7 @@ public interface OrmQueryEngine {
|
||||
/**
|
||||
* Execute the find id's query.
|
||||
*/
|
||||
<T> BeanIdList findIds(OrmQueryRequest<T> request);
|
||||
<A> List<A> findIds(OrmQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Execute the query as a delete statement.
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -12,7 +13,6 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
@@ -304,9 +304,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return queryEngine.findRowCount(this);
|
||||
}
|
||||
|
||||
public List<Object> findIds() {
|
||||
BeanIdList idList = queryEngine.findIds(this);
|
||||
return idList.getIdList();
|
||||
public <A> List<A> findIds() {
|
||||
return queryEngine.findIds(this);
|
||||
}
|
||||
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
@@ -373,6 +372,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return (Map<?, ?>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
*/
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return queryEngine.findSingleAttributeList(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean specific finder if one has been set.
|
||||
*/
|
||||
@@ -520,4 +527,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
public String getBaseTableAlias() {
|
||||
return query.getAlias() == null ? beanDescriptor.getBaseTableAlias() : query.getAlias();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JDBC buffer fetchSize hint if not set explicitly.
|
||||
*/
|
||||
public void setDefaultFetchBuffer(int fetchSize) {
|
||||
query.setDefaultFetchBuffer(fetchSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
|
||||
/**
|
||||
* Deferred update of a relationship where an Id value is not initially available
|
||||
* so instead we execute this later as a SqlUpdate statement.
|
||||
*/
|
||||
public class PersistDeferredRelationship {
|
||||
|
||||
private final SpiEbeanServer ebeanServer;
|
||||
private final BeanDescriptor<?> beanDescriptor;
|
||||
private final EntityBean assocBean;
|
||||
private final ImportedId importedId;
|
||||
private final EntityBean bean;
|
||||
|
||||
public PersistDeferredRelationship(SpiEbeanServer ebeanServer, BeanDescriptor<?> beanDescriptor, EntityBean assocBean, ImportedId importedId, EntityBean bean) {
|
||||
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.beanDescriptor = beanDescriptor;
|
||||
this.assocBean = assocBean;
|
||||
this.importedId = importedId;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and execute a SqlUpdate to set the importId value (as it will be available now).
|
||||
* <p>
|
||||
* This is executed later (deferred) until after JDBC batch flush or prior to commit.
|
||||
* </p>
|
||||
*/
|
||||
public void execute(SpiTransaction transaction) {
|
||||
|
||||
String sql = beanDescriptor.getUpdateImportedIdSql(importedId);
|
||||
SqlUpdate sqlUpdate = ebeanServer.createSqlUpdate(sql);
|
||||
|
||||
// bind the set clause for the importedId
|
||||
int pos = importedId.bind(1, sqlUpdate, assocBean);
|
||||
|
||||
// bind the where clause for the bean
|
||||
Object[] idValues = beanDescriptor.getIdBinder().getIdValues(bean);
|
||||
for (int j = 0; j < idValues.length; j++) {
|
||||
sqlUpdate.setParameter(pos + j, idValues[j]);
|
||||
}
|
||||
|
||||
ebeanServer.execute(sqlUpdate, transaction);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebeaninternal.api.ConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PreGetterCallback;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanPersistRequest;
|
||||
import com.avaje.ebean.event.changelog.BeanChange;
|
||||
import com.avaje.ebeaninternal.api.DerivedRelationshipData;
|
||||
import com.avaje.ebeaninternal.api.ConcurrencyMode;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEvent;
|
||||
@@ -18,12 +18,13 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
import com.avaje.ebeaninternal.server.persist.PersistExecute;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanPersistIdMap;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdate;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdate;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
@@ -36,7 +37,7 @@ import java.util.Set;
|
||||
/**
|
||||
* PersistRequest for insert update or delete of a bean.
|
||||
*/
|
||||
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate {
|
||||
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate, PreGetterCallback {
|
||||
|
||||
private final BeanManager<T> beanManager;
|
||||
|
||||
@@ -137,6 +138,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private long version;
|
||||
|
||||
/**
|
||||
* Flag set when request is added to JDBC batch registered as a "getter callback" to automatically flush batch.
|
||||
*/
|
||||
private boolean getterCallback;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) {
|
||||
|
||||
@@ -174,7 +180,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
/**
|
||||
* Return the document store event that should be used for this request.
|
||||
*
|
||||
* <p>
|
||||
* Used to check if the Transaction has set the mode to IGNORE when doing large batch inserts that we
|
||||
* don't want to send to the doc store.
|
||||
*/
|
||||
@@ -239,8 +245,17 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
public void setBatched() {
|
||||
batched = true;
|
||||
if (type == Type.INSERT || type == Type.UPDATE) {
|
||||
// used to trigger automatic jdbc batch flush
|
||||
intercept.registerGetterCallback(this);
|
||||
getterCallback = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetterTrigger() {
|
||||
transaction.flushBatch();
|
||||
}
|
||||
|
||||
public void setSkipBatchForTopLevel() {
|
||||
skipBatchForTopLevel = true;
|
||||
@@ -548,7 +563,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Create and return a new reference bean matching this beans Id value.
|
||||
*/
|
||||
public T createReference() {
|
||||
return beanDescriptor.createReference(Boolean.FALSE, getBeanId(), null);
|
||||
return beanDescriptor.createReference(Boolean.FALSE, false, getBeanId(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,6 +636,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
if (getterCallback) {
|
||||
intercept.clearGetterCallback();
|
||||
}
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
persistExecute.executeInsertBean(this);
|
||||
@@ -803,7 +821,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache,
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to sync Cache,
|
||||
* Cluster and text indexes.
|
||||
*/
|
||||
private void addEvent() {
|
||||
@@ -856,8 +874,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
}
|
||||
|
||||
public List<DerivedRelationshipData> getDerivedRelationships() {
|
||||
return transaction.getDerivedRelationship(bean);
|
||||
/**
|
||||
* Register the derived relationships to get executed later (on JDBC batch flush or commit).
|
||||
*/
|
||||
public void deferredRelationship(EntityBean assocBean, ImportedId importedId, EntityBean bean) {
|
||||
transaction.registerDeferred(new PersistDeferredRelationship(ebeanServer, beanDescriptor, assocBean, importedId, bean));
|
||||
}
|
||||
|
||||
private void postInsert() {
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user