mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93ae5f2b7c | ||
|
|
bc302b19db |
@@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
java_version: [21]
|
||||
java_version: [11]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-clickhouse</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-db2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-hana</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-mariadb</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-mysql</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-nuodb</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-oracle</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -47,19 +47,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis-types</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlite</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -42,13 +42,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<relativePath>../..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -41,7 +41,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -60,13 +60,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>composites</artifactId>
|
||||
|
||||
+1
-48
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
@@ -126,53 +126,6 @@
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<release>11</release>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>compile-21</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<release>21</release>
|
||||
<compileSourceRoots>
|
||||
<compileSourceRoot>${project.basedir}/src/main/java21</compileSourceRoot>
|
||||
</compileSourceRoots>
|
||||
<multiReleaseOutput>true</multiReleaseOutput>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<addMavenDescriptor>false</addMavenDescriptor>
|
||||
<manifestEntries>
|
||||
<Multi-Release>true</Multi-Release>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
<!-- <manifest>-->
|
||||
<!-- <addDefaultImplementationEntries>true</addDefaultImplementationEntries>-->
|
||||
<!-- </manifest>-->
|
||||
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
final class DInsertOptionsBuilder implements InsertOptions.Builder {
|
||||
|
||||
private Boolean getGeneratedKeys;
|
||||
private boolean onConflictUpdate;
|
||||
private boolean onConflictNothing;
|
||||
private String constraint;
|
||||
private String uniqueColumns;
|
||||
private String updateSet;
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder onConflictNothing() {
|
||||
this.onConflictNothing = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder onConflictUpdate() {
|
||||
this.onConflictUpdate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder constraint(String constraint) {
|
||||
this.constraint = constraint;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder uniqueColumns(String uniqueColumns) {
|
||||
this.uniqueColumns = uniqueColumns;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder updateSet(String updateSet) {
|
||||
this.updateSet = updateSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions.Builder getGeneratedKeys(boolean getGeneratedKeys) {
|
||||
this.getGeneratedKeys = getGeneratedKeys;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertOptions build() {
|
||||
return new Options(constraint, uniqueColumns, updateSet, onConflictUpdate, onConflictNothing, getGeneratedKeys);
|
||||
}
|
||||
|
||||
static final class Options implements InsertOptions {
|
||||
|
||||
private static final String UPDATE = "U";
|
||||
private static final String NOTHING = "N";
|
||||
private static final String NORMAL = "_";
|
||||
private final String key;
|
||||
private final Boolean getGeneratedKeys;
|
||||
private final String constraint;
|
||||
private final String uniqueColumns;
|
||||
private final String updateSet;
|
||||
|
||||
Options(String constraint, String uniqueColumns, String updateSet, boolean onConflictUpdate, boolean onConflictNothing, Boolean getGeneratedKeys) {
|
||||
this.constraint = constraint;
|
||||
this.uniqueColumns = uniqueColumns;
|
||||
this.updateSet = updateSet;
|
||||
this.getGeneratedKeys = getGeneratedKeys;
|
||||
this.key = (onConflictUpdate ? UPDATE : onConflictNothing ? NOTHING : NORMAL)
|
||||
+ '+' + plus(constraint)
|
||||
+ '+' + plus(uniqueColumns)
|
||||
+ '+' + plus(updateSet);
|
||||
}
|
||||
|
||||
private String plus(String val) {
|
||||
return val == null ? "" : val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String constraint() {
|
||||
return constraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uniqueColumns() {
|
||||
return uniqueColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String updateSet() {
|
||||
return updateSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getGetGeneratedKeys() {
|
||||
return getGeneratedKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1227,53 +1227,22 @@ public interface Database {
|
||||
*/
|
||||
void insert(Object bean);
|
||||
|
||||
/**
|
||||
* Insert the bean with options (ON CONFLICT DO UPDATE | DO NOTHING).
|
||||
* <p>
|
||||
* Currently, this is limited to use with Postgres only,
|
||||
* <p>
|
||||
* When using this ebean will look to determine the unique columns by looking at
|
||||
* the mapping like {@code @Column(unique=true} and {@code @Index(unique=true}.
|
||||
*/
|
||||
void insert(Object bean, InsertOptions insertOptions);
|
||||
|
||||
/**
|
||||
* Insert the bean with a transaction.
|
||||
*/
|
||||
void insert(Object bean, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction.
|
||||
* <p>
|
||||
* Currently, this is limited to use with Postgres only,
|
||||
*/
|
||||
void insert(Object bean, InsertOptions insertOptions, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans. If there is no current transaction one is created and used to
|
||||
* insert all the beans in the collection.
|
||||
*/
|
||||
void insertAll(Collection<?> beans);
|
||||
|
||||
/**
|
||||
* Insert the beans with options - typically ON CONFLICT DO UPDATE | DO NOTHING.
|
||||
* <p>
|
||||
* Currently, this is limited to use with Postgres only,
|
||||
*/
|
||||
void insertAll(Collection<?> beans, InsertOptions options);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans with an explicit transaction.
|
||||
*/
|
||||
void insertAll(Collection<?> beans, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert the beans with options (ON CONFLICT DO UPDATE | DO NOTHING) and transaction.
|
||||
* <p>
|
||||
* Currently, this is limited to use with Postgres only,
|
||||
*/
|
||||
void insertAll(Collection<?> beans, InsertOptions options, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute explicitly passing a transaction.
|
||||
*/
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.avaje.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Options to be used with insert such as ON CONFLICT DO UPDATE | NOTHING.
|
||||
*/
|
||||
public interface InsertOptions {
|
||||
|
||||
/**
|
||||
* Use ON CONFLICT UPDATE with automatic determination of the unique columns to conflict on.
|
||||
* <p>
|
||||
* Uses mapping to determine the unique columns - {@code @Column(unique=true)} and {@code @Index(unique=true)} .
|
||||
*/
|
||||
InsertOptions ON_CONFLICT_UPDATE = InsertOptions.builder()
|
||||
.onConflictUpdate()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Use ON CONFLICT DO NOTHING with automatic determination of the unique columns to conflict on.
|
||||
* <p>
|
||||
* Uses mapping to determine the unique columns - {@code @Column(unique=true)} and {@code @Index(unique=true)} .
|
||||
*/
|
||||
InsertOptions ON_CONFLICT_NOTHING = InsertOptions.builder()
|
||||
.onConflictNothing()
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Return a builder for InsertOptions.
|
||||
*/
|
||||
static Builder builder() {
|
||||
return new DInsertOptionsBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the constraint name that is used for ON CONFLICT.
|
||||
*/
|
||||
@Nullable
|
||||
String constraint();
|
||||
|
||||
/**
|
||||
* Return the unique columns that is used for ON CONFLICT.
|
||||
* <p>
|
||||
* When not explicitly set will use mapping like {@code @Column(unique=true)} to determine the
|
||||
* non-unique columns.
|
||||
*/
|
||||
@Nullable
|
||||
String uniqueColumns();
|
||||
|
||||
/**
|
||||
* Return the ON CONFLICT UPDATE SET clause.
|
||||
* <p>
|
||||
* When not set will use the non-unique columns.
|
||||
*/
|
||||
@Nullable
|
||||
String updateSet();
|
||||
|
||||
/**
|
||||
* Return if GetGeneratedKeys should be used to fetch the generated keys after insert.
|
||||
*/
|
||||
@Nullable
|
||||
Boolean getGetGeneratedKeys();
|
||||
|
||||
/**
|
||||
* Return the key for these build options.
|
||||
*/
|
||||
String key();
|
||||
|
||||
/**
|
||||
* The builder for InsertOptions.
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
/**
|
||||
* Use a ON CONFLICT UPDATE automatically determining the unique columns.
|
||||
*/
|
||||
Builder onConflictUpdate();
|
||||
|
||||
/**
|
||||
* Use a ON CONFLICT DO NOTHING automatically determining the unique columns.
|
||||
*/
|
||||
Builder onConflictNothing();
|
||||
|
||||
/**
|
||||
* Specify an explicit conflict constraint name.
|
||||
* <p>
|
||||
* When this is used then unique columns will not be used.
|
||||
*/
|
||||
Builder constraint(String constraint);
|
||||
|
||||
/**
|
||||
* Specify the unique columns for the conflict target.
|
||||
* <p>
|
||||
* When not specified and constraint is also not specified then
|
||||
* it will automatically determine the unique columns
|
||||
* based on mapping like {@code @Column(unique=true)} and
|
||||
* {@code @Index(unique=true)} .
|
||||
*/
|
||||
Builder uniqueColumns(String uniqueColumns);
|
||||
|
||||
/**
|
||||
* Specify the ON CONFLICT DO UPDATE SET clause.
|
||||
* <p>
|
||||
* When not specified ebean will include all the non-unique columns.
|
||||
*/
|
||||
Builder updateSet(String updateSet);
|
||||
|
||||
/**
|
||||
* Specify if GetGeneratedKeys should be used to return generated keys.
|
||||
*/
|
||||
Builder getGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* Build and return the insert options.
|
||||
*/
|
||||
InsertOptions build();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,9 @@ public interface ModifyAwareType {
|
||||
*/
|
||||
void setMarkedDirty(boolean markedDirty);
|
||||
|
||||
/**
|
||||
* Return a unmodifiable version of this type.
|
||||
*/
|
||||
Object freeze();
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
|
||||
@@ -54,6 +55,24 @@ public interface Transaction extends AutoCloseable {
|
||||
*/
|
||||
int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
|
||||
/**
|
||||
* Experimental Feature - Freeze the beans in the persistence context and detach them.
|
||||
*/
|
||||
@Deprecated(since = "Experimental Feature")
|
||||
default FrozenBeans freezeAndDetach() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental Feature - Attach frozen beans to the persistence context so that they can be
|
||||
* used with ORM queries (with the persistence context acting like a cache).
|
||||
*/
|
||||
@Deprecated(since = "Experimental Feature")
|
||||
default void attach(FrozenBeans frozenBeans) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,11 @@ public interface BeanCollection<E> extends Serializable, ToStringAware {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a unmodifiable collection of the underlying entities.
|
||||
*/
|
||||
Object freeze();
|
||||
|
||||
/**
|
||||
* Set the disableLazyLoad state.
|
||||
*/
|
||||
|
||||
@@ -552,4 +552,16 @@ public interface EntityBeanIntercept extends Serializable {
|
||||
* Update the 'next' mutable info returning the content that was obtained via dirty detection.
|
||||
*/
|
||||
String mutableNext(int propertyIndex);
|
||||
|
||||
/**
|
||||
* Set that lazy loading if invoked throws a PersistenceException.
|
||||
*/
|
||||
void errorOnLazyLoad(boolean lazyLoadAsError);
|
||||
|
||||
/**
|
||||
* Freeze the intercept so that it is readOnly.
|
||||
* Lazy loading and mutation of the bean is not allowed.
|
||||
*/
|
||||
void freeze();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Holds entity beans that are frozen.
|
||||
*/
|
||||
public interface FrozenBeans extends Serializable {
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Base EntityBeanIntercept that supports partial loaded state and lazy loading.
|
||||
*/
|
||||
abstract class InterceptBase implements EntityBeanIntercept {
|
||||
|
||||
/**
|
||||
* Flag for loaded property.
|
||||
*/
|
||||
static final byte FLAG_LOADED_PROP = 1;
|
||||
|
||||
/**
|
||||
* The actual entity bean that 'owns' this intercept.
|
||||
*/
|
||||
protected final EntityBean owner;
|
||||
protected final byte[] flags;
|
||||
protected boolean readOnly;
|
||||
protected boolean disableLazyLoad;
|
||||
protected boolean errorOnLazyLoad;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private String ebeanServerName;
|
||||
private transient BeanLoader beanLoader;
|
||||
private transient PersistenceContext persistenceContext;
|
||||
|
||||
/**
|
||||
* Flag set when lazy loading failed due to the underlying bean being deleted in the DB.
|
||||
*/
|
||||
protected boolean lazyLoadFailure;
|
||||
protected boolean fullyLoadedBean;
|
||||
protected int lazyLoadProperty = -1;
|
||||
protected Object ownerId;
|
||||
|
||||
/**
|
||||
* Create with a given entity.
|
||||
*/
|
||||
InterceptBase(Object ownerBean) {
|
||||
this.owner = (EntityBean) ownerBean;
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Constructor only for use by serialization frameworks.
|
||||
*/
|
||||
InterceptBase() {
|
||||
this.owner = null;
|
||||
this.flags = null;
|
||||
}
|
||||
|
||||
public void freeze() {
|
||||
this.errorOnLazyLoad = true;
|
||||
this.readOnly = true;
|
||||
this.beanLoader = null;
|
||||
this.persistenceContext = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final EntityBean owner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object ownerId() {
|
||||
return ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setOwnerId(Object ownerId) {
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBeanLoader(BeanLoader beanLoader) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.ebeanServerName = beanLoader.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.persistenceContext = ctx;
|
||||
this.ebeanServerName = beanLoader.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PersistenceContext persistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPersistenceContext(PersistenceContext persistenceContext) {
|
||||
this.persistenceContext = persistenceContext;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean isFullyLoadedBean() {
|
||||
return fullyLoadedBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setFullyLoadedBean(boolean fullyLoadedBean) {
|
||||
this.fullyLoadedBean = fullyLoadedBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isPartial() {
|
||||
for (byte flag : flags) {
|
||||
if ((flag & FLAG_LOADED_PROP) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasIdOnly(int idIndex) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if (i == idIndex) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) == 0) return false;
|
||||
} else if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setLazyLoadFailure(Object ownerId) {
|
||||
this.lazyLoadFailure = true;
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isLazyLoadFailure() {
|
||||
return lazyLoadFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isDisableLazyLoad() {
|
||||
return disableLazyLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
this.disableLazyLoad = disableLazyLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void errorOnLazyLoad(boolean errorOnLazyLoad) {
|
||||
this.errorOnLazyLoad = errorOnLazyLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setEmbeddedLoaded(Object embeddedBean) {
|
||||
if (embeddedBean instanceof EntityBean) {
|
||||
((EntityBean) embeddedBean)._ebean_getIntercept().setLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int findProperty(String propertyName) {
|
||||
final String[] names = owner._ebean_getPropertyNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (names[i].equals(propertyName)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String property(int propertyIndex) {
|
||||
if (propertyIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
return owner._ebean_getPropertyName(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int propertyLength() {
|
||||
return flags.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPropertyLoaded(String propertyName, boolean loaded) {
|
||||
final int position = findProperty(propertyName);
|
||||
if (position == -1) {
|
||||
throw new IllegalArgumentException("Property " + propertyName + " not found");
|
||||
}
|
||||
if (loaded) {
|
||||
flags[position] |= FLAG_LOADED_PROP;
|
||||
} else {
|
||||
flags[position] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setPropertyUnloaded(int propertyIndex) {
|
||||
flags[propertyIndex] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void initialisedMany(int propertyIndex) {
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setLoadedProperty(int propertyIndex) {
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setLoadedPropertyAll() {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isLoadedProperty(int propertyIndex) {
|
||||
return (flags[propertyIndex] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<String> loadedPropertyNames() {
|
||||
if (fullyLoadedBean) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> props = new LinkedHashSet<>();
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
props.add(property(i));
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final StringBuilder loadedPropertyKey() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int len = propertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (isLoadedProperty(i)) {
|
||||
sb.append(i).append(',');
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean[] loaded() {
|
||||
final boolean[] ret = new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int lazyLoadPropertyIndex() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String lazyLoadProperty() {
|
||||
return property(lazyLoadProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void loadBean(int loadProperty) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (errorOnLazyLoad) {
|
||||
throw new PersistenceException("Lazy loading not allowed on this bean");
|
||||
}
|
||||
if (beanLoader == null) {
|
||||
final Database database = DB.byName(ebeanServerName);
|
||||
if (database == null) {
|
||||
throw new PersistenceException(ebeanServerName == null ? "No registered default server" : "Database [" + ebeanServerName + "] is not registered");
|
||||
}
|
||||
// For stand alone reference bean or after deserialisation lazy load
|
||||
// using the ebeanServer. Synchronise only on the bean.
|
||||
loadBeanInternal(loadProperty, database.pluginApi().beanLoader());
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
final Lock lock = beanLoader.lock();
|
||||
try {
|
||||
// Lazy loading using LoadBeanContext which supports batch loading
|
||||
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
|
||||
loadBeanInternal(loadProperty, beanLoader);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void loadBeanInternal(int loadProperty, BeanLoader loader) {
|
||||
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
|
||||
// race condition where multiple threads calling preGetter concurrently
|
||||
return;
|
||||
}
|
||||
if (lazyLoadFailure) {
|
||||
// failed when batch lazy loaded by another bean in the batch
|
||||
throw new EntityNotFoundException("(Lazy) loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
|
||||
}
|
||||
if (lazyLoadProperty == -1) {
|
||||
lazyLoadProperty = loadProperty;
|
||||
loader.loadBean(this);
|
||||
if (lazyLoadFailure) {
|
||||
// failed when lazy loading this bean
|
||||
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
|
||||
}
|
||||
// bean should be loaded and intercepting now. setLoaded() has
|
||||
// been called by the lazy loading mechanism
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,55 +10,110 @@ import java.util.Set;
|
||||
* EntityBeanIntercept optimised for read only use.
|
||||
* <p>
|
||||
* For the read only use this intercept doesn't need to hold any state that is normally
|
||||
* required for updates such as per property changed, loaded, dirty state, original values
|
||||
* required for updates such as per property changed, dirty state, original values
|
||||
* bean state etc.
|
||||
*/
|
||||
public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
private final EntityBean owner;
|
||||
public final class InterceptReadOnly extends InterceptBase {
|
||||
|
||||
/**
|
||||
* Create with a given entity.
|
||||
*/
|
||||
public InterceptReadOnly(Object ownerBean) {
|
||||
this.owner = (EntityBean) ownerBean;
|
||||
super(ownerBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InterceptReadOnly{" + owner + '}';
|
||||
public void preGetId() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBean owner() {
|
||||
return owner;
|
||||
public void preGetter(int propertyIndex) {
|
||||
if (disableLazyLoad) {
|
||||
return;
|
||||
}
|
||||
if (!isLoadedProperty(propertyIndex)) {
|
||||
loadBean(propertyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void preSetter(int propertyIndex) {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
}
|
||||
setLoadedProperty(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext persistenceContext() {
|
||||
return null;
|
||||
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPersistenceContext(PersistenceContext persistenceContext) {
|
||||
|
||||
public void preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
|
||||
preSetter(propertyIndex);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// The following method have "Do Nothing" behaviour as not interested in mutation state
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void setNodeUsageCollector(NodeUsageCollector usageCollector) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object ownerId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwnerId(Object ownerId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object embeddedOwner() {
|
||||
return null;
|
||||
@@ -84,31 +139,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanLoader(BeanLoader beanLoader) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullyLoadedBean() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullyLoadedBean(boolean fullyLoadedBean) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPartial() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return false;
|
||||
@@ -134,11 +164,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasIdOnly(int idIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReference() {
|
||||
return false;
|
||||
@@ -159,16 +184,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForceUpdate(boolean forceUpdate) {
|
||||
|
||||
@@ -199,31 +214,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLazyLoadFailure(Object ownerId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadFailure() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableLazyLoad() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmbeddedLoaded(Object embeddedBean) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbeddedNewOrDirty(Object embeddedBean) {
|
||||
return false;
|
||||
@@ -234,45 +224,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findProperty(String propertyName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String property(int propertyIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int propertyLength() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyLoaded(String propertyName, boolean loaded) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyUnloaded(int propertyIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadedProperty(int propertyIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadedPropertyAll() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoadedProperty(int propertyIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangedProperty(int propertyIndex) {
|
||||
@@ -319,11 +270,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> loadedPropertyNames() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] dirtyProperties() {
|
||||
return new boolean[0];
|
||||
@@ -369,61 +315,11 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder loadedPropertyKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] loaded() {
|
||||
return new boolean[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lazyLoadPropertyIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lazyLoadProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(int loadProperty) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBeanInternal(int loadProperty, BeanLoader loader) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetterCallback(int propertyIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetId() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetter(int propertyIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
|
||||
|
||||
@@ -434,61 +330,6 @@ public class InterceptReadOnly implements EntityBeanIntercept {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOldValue(int propertyIndex, Object oldValue) {
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.ValuePair;
|
||||
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -13,8 +9,6 @@ import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* This is the object added to every entity bean using byte code enhancement.
|
||||
@@ -22,7 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* This provides the mechanisms to support deferred fetching of reference beans
|
||||
* and oldValues generation for concurrency checking.
|
||||
*/
|
||||
public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
public final class InterceptReadWrite extends InterceptBase {
|
||||
|
||||
private static final long serialVersionUID = -3664031775464862649L;
|
||||
|
||||
@@ -30,10 +24,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
/**
|
||||
* Used when a bean is partially loaded.
|
||||
*/
|
||||
private static final byte FLAG_LOADED_PROP = 1;
|
||||
private static final byte FLAG_CHANGED_PROP = 2;
|
||||
private static final byte FLAG_CHANGEDLOADED_PROP = 3;
|
||||
/**
|
||||
@@ -47,43 +37,21 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
*/
|
||||
private static final byte FLAG_MUTABLE_HASH_SET = 16;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
private transient PersistenceContext persistenceContext;
|
||||
private transient BeanLoader beanLoader;
|
||||
private transient PreGetterCallback preGetterCallback;
|
||||
|
||||
private String ebeanServerName;
|
||||
private boolean deletedFromCollection;
|
||||
|
||||
/**
|
||||
* The actual entity bean that 'owns' this intercept.
|
||||
*/
|
||||
private final EntityBean owner;
|
||||
private EntityBean embeddedOwner;
|
||||
private int embeddedOwnerIndex;
|
||||
/**
|
||||
* One of NEW, REF, UPD.
|
||||
* One of NEW, REF, LOADED.
|
||||
*/
|
||||
private int state;
|
||||
private boolean deletedFromCollection;
|
||||
private boolean forceUpdate;
|
||||
private boolean readOnly;
|
||||
private boolean dirty;
|
||||
/**
|
||||
* Flag set to disable lazy loading.
|
||||
*/
|
||||
private boolean disableLazyLoad;
|
||||
/**
|
||||
* Flag set when lazy loading failed due to the underlying bean being deleted in the DB.
|
||||
*/
|
||||
private boolean lazyLoadFailure;
|
||||
private boolean fullyLoadedBean;
|
||||
private boolean loadedFromCache;
|
||||
private final byte[] flags;
|
||||
private Object[] origValues;
|
||||
private Exception[] loadErrors;
|
||||
private int lazyLoadProperty = -1;
|
||||
private Object ownerId;
|
||||
private int sortOrder;
|
||||
|
||||
/**
|
||||
@@ -101,49 +69,14 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
* Create with a given entity.
|
||||
*/
|
||||
public InterceptReadWrite(Object ownerBean) {
|
||||
this.owner = (EntityBean) ownerBean;
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
super(ownerBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL - Constructor only for use by serialization frameworks.
|
||||
*/
|
||||
public InterceptReadWrite() {
|
||||
this.owner = null;
|
||||
this.flags = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InterceptReadWrite@" + hashCode() + "{state=" + state +
|
||||
(dirty ? " dirty;" : "") +
|
||||
(forceUpdate ? " forceUpdate;" : "") +
|
||||
(readOnly ? " readOnly;" : "") +
|
||||
(disableLazyLoad ? " disableLazyLoad;" : "") +
|
||||
(lazyLoadFailure ? " lazyLoadFailure;" : "") +
|
||||
(fullyLoadedBean ? " fullyLoadedBean;" : "") +
|
||||
(loadedFromCache ? " loadedFromCache;" : "") +
|
||||
", pc=" + System.identityHashCode(persistenceContext) +
|
||||
", flags=" + Arrays.toString(flags) +
|
||||
(lazyLoadProperty > -1 ? (", lazyLoadProperty=" + lazyLoadProperty) : "") +
|
||||
", loader=" + beanLoader +
|
||||
(ownerId != null ? (", ownerId=" + ownerId) : "") +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBean owner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext persistenceContext() {
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPersistenceContext(PersistenceContext persistenceContext) {
|
||||
this.persistenceContext = persistenceContext;
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,16 +84,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
this.nodeUsageCollector = usageCollector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object ownerId() {
|
||||
return ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwnerId(Object ownerId) {
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object embeddedOwner() {
|
||||
return embeddedOwner;
|
||||
@@ -187,39 +110,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
this.embeddedOwnerIndex = embeddedOwnerIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.persistenceContext = ctx;
|
||||
this.ebeanServerName = beanLoader.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanLoader(BeanLoader beanLoader) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.ebeanServerName = beanLoader.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullyLoadedBean() {
|
||||
return fullyLoadedBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullyLoadedBean(boolean fullyLoadedBean) {
|
||||
this.fullyLoadedBean = fullyLoadedBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPartial() {
|
||||
for (byte flag : flags) {
|
||||
if ((flag & FLAG_LOADED_PROP) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
if (dirty) {
|
||||
@@ -257,18 +147,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
return isNew() || isDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasIdOnly(int idIndex) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if (i == idIndex) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) == 0) return false;
|
||||
} else if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReference() {
|
||||
return state == STATE_REFERENCE;
|
||||
@@ -298,16 +176,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
return loadedFromCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForceUpdate(boolean forceUpdate) {
|
||||
this.forceUpdate = forceUpdate;
|
||||
@@ -356,34 +224,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
this.lazyLoadProperty = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLazyLoadFailure(Object ownerId) {
|
||||
this.lazyLoadFailure = true;
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadFailure() {
|
||||
return lazyLoadFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableLazyLoad() {
|
||||
return disableLazyLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisableLazyLoad(boolean disableLazyLoad) {
|
||||
this.disableLazyLoad = disableLazyLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmbeddedLoaded(Object embeddedBean) {
|
||||
if (embeddedBean instanceof EntityBean) {
|
||||
((EntityBean) embeddedBean)._ebean_getIntercept().setLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbeddedNewOrDirty(Object embeddedBean) {
|
||||
if (embeddedBean == null) {
|
||||
@@ -411,65 +251,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
return origValues[propertyIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findProperty(String propertyName) {
|
||||
final String[] names = owner._ebean_getPropertyNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (names[i].equals(propertyName)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String property(int propertyIndex) {
|
||||
if (propertyIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
return owner._ebean_getPropertyName(propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int propertyLength() {
|
||||
return flags.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyLoaded(String propertyName, boolean loaded) {
|
||||
final int position = findProperty(propertyName);
|
||||
if (position == -1) {
|
||||
throw new IllegalArgumentException("Property " + propertyName + " not found");
|
||||
}
|
||||
if (loaded) {
|
||||
flags[position] |= FLAG_LOADED_PROP;
|
||||
} else {
|
||||
flags[position] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyUnloaded(int propertyIndex) {
|
||||
flags[propertyIndex] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadedProperty(int propertyIndex) {
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadedPropertyAll() {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoadedProperty(int propertyIndex) {
|
||||
return (flags[propertyIndex] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangedProperty(int propertyIndex) {
|
||||
return (flags[propertyIndex] & FLAG_CHANGED_PROP) != 0;
|
||||
@@ -530,20 +311,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> loadedPropertyNames() {
|
||||
if (fullyLoadedBean) {
|
||||
return null;
|
||||
}
|
||||
final Set<String> props = new LinkedHashSet<>();
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
props.add(property(i));
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] dirtyProperties() {
|
||||
final int len = propertyLength();
|
||||
@@ -668,86 +435,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder loadedPropertyKey() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int len = propertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (isLoadedProperty(i)) {
|
||||
sb.append(i).append(',');
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] loaded() {
|
||||
final boolean[] ret = new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lazyLoadPropertyIndex() {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lazyLoadProperty() {
|
||||
return property(lazyLoadProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(int loadProperty) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (beanLoader == null) {
|
||||
final Database database = DB.byName(ebeanServerName);
|
||||
if (database == null) {
|
||||
throw new PersistenceException(ebeanServerName == null ? "No registered default server" : "Database [" + ebeanServerName + "] is not registered");
|
||||
}
|
||||
// For stand alone reference bean or after deserialisation lazy load
|
||||
// using the ebeanServer. Synchronise only on the bean.
|
||||
loadBeanInternal(loadProperty, database.pluginApi().beanLoader());
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
final Lock lock = beanLoader.lock();
|
||||
try {
|
||||
// Lazy loading using LoadBeanContext which supports batch loading
|
||||
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
|
||||
loadBeanInternal(loadProperty, beanLoader);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBeanInternal(int loadProperty, BeanLoader loader) {
|
||||
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
|
||||
// race condition where multiple threads calling preGetter concurrently
|
||||
return;
|
||||
}
|
||||
if (lazyLoadFailure) {
|
||||
// failed when batch lazy loaded by another bean in the batch
|
||||
throw new EntityNotFoundException("(Lazy) loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
|
||||
}
|
||||
if (lazyLoadProperty == -1) {
|
||||
lazyLoadProperty = loadProperty;
|
||||
loader.loadBean(this);
|
||||
if (lazyLoadFailure) {
|
||||
// failed when lazy loading this bean
|
||||
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
|
||||
}
|
||||
// bean should be loaded and intercepting now. setLoaded() has
|
||||
// been called by the lazy loading mechanism
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if two objects are equal.
|
||||
*/
|
||||
@@ -808,11 +495,6 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetterCallback(int propertyIndex) {
|
||||
PreGetterCallback preGetterCallback = this.preGetterCallback;
|
||||
@@ -1076,4 +758,16 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
|
||||
final MutableValueNext next = mutableNext[propertyIndex];
|
||||
return next != null ? next.content() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freeze() {
|
||||
super.freeze();
|
||||
// not allowed to be used for updates
|
||||
this.dirty = false;
|
||||
this.forceUpdate = false;
|
||||
this.deletedFromCollection = false;
|
||||
this.origValues = null;
|
||||
this.nodeUsageCollector = null;
|
||||
this.embeddedOwner = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
builder.addCollection(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object freeze() {
|
||||
// null -> illegal to access reference collection
|
||||
return list == null ? null : Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
@@ -141,16 +147,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
}
|
||||
|
||||
public BeanCollectionAdd collectionAdd() {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void refresh(ModifyListenMode modifyListenMode, BeanList<E> newList) {
|
||||
setModifyListening(modifyListenMode);
|
||||
this.list = newList.actualList();
|
||||
/**
|
||||
* Set the actual underlying list.
|
||||
* <p>
|
||||
* This is primarily for the deferred fetching function.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualList(List<?> list) {
|
||||
this.list = (List<E>) list;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.bean.*;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.ToStringBuilder;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -14,12 +17,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
/**
|
||||
* The underlying map implementation.
|
||||
*/
|
||||
private LinkedHashMap<K, E> map;
|
||||
private Map<K, E> map;
|
||||
|
||||
/**
|
||||
* Create with a given Map.
|
||||
*/
|
||||
public BeanMap(LinkedHashMap<K, E> map) {
|
||||
public BeanMap(Map<K, E> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@@ -34,6 +37,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
super(ebeanServer, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object freeze() {
|
||||
// null -> illegal to access reference collection
|
||||
return map == null ? null : Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(ToStringBuilder builder) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
@@ -157,23 +166,18 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedHashMap<K, E> collectionAdd() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual underlying map. Used for performing lazy fetch.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
|
||||
setModifyListening(modifyListenMode);
|
||||
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
|
||||
public void setActualMap(Map<?, ?> map) {
|
||||
this.map = (Map<K, E>) map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying map.
|
||||
*/
|
||||
public LinkedHashMap<K, E> actualMap() {
|
||||
public Map<K, E> actualMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
/**
|
||||
* The underlying Set implementation.
|
||||
*/
|
||||
private LinkedHashSet<E> set;
|
||||
private Set<E> set;
|
||||
|
||||
/**
|
||||
* Create with a specific Set implementation.
|
||||
*/
|
||||
public BeanSet(LinkedHashSet<E> set) {
|
||||
public BeanSet(Set<E> set) {
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
builder.addCollection(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object freeze() {
|
||||
// null -> illegal to access reference collection
|
||||
return set == null ? null : Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
@@ -141,22 +147,18 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
}
|
||||
|
||||
public BeanCollectionAdd collectionAdd() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
|
||||
setModifyListening(modifyListenMode);
|
||||
this.set = newSet.actualSet();
|
||||
/**
|
||||
* Set the underlying set (used for lazy fetch).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualSet(Set<?> set) {
|
||||
this.set = (Set<E>) set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying set.
|
||||
*/
|
||||
public LinkedHashSet<E> actualSet() {
|
||||
public Set<E> actualSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.ToStringBuilder;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Map capable of lazy loading and modification aware.
|
||||
*/
|
||||
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements SequencedMap<K, E> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying map implementation.
|
||||
*/
|
||||
private LinkedHashMap<K, E> map;
|
||||
|
||||
/**
|
||||
* Create with a given Map.
|
||||
*/
|
||||
public BeanMap(LinkedHashMap<K, E> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using a underlying LinkedHashMap.
|
||||
*/
|
||||
public BeanMap() {
|
||||
this(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
|
||||
super(ebeanServer, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(ToStringBuilder builder) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
builder.addRaw("{}");
|
||||
} else {
|
||||
builder.addRaw("{");
|
||||
for (Entry<K, E> entry : map.entrySet()) {
|
||||
builder.add(String.valueOf(entry.getKey()), entry.getValue());
|
||||
}
|
||||
builder.addRaw("}");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipSave() {
|
||||
return map == null || (map.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
BeanMap<K, E> otherMap = (BeanMap<K, E>) other;
|
||||
internalPutNull();
|
||||
map.putAll(otherMap.actualMap());
|
||||
}
|
||||
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
if (key != null) {
|
||||
map.put((K) key, (E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void internalPutWithCheck(Object key, Object bean) {
|
||||
if (map == null || key == null || !map.containsKey(key)) {
|
||||
internalPut(key, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAdd(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying map has been populated. Returns false if it
|
||||
* has a deferred fetch pending.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPopulated() {
|
||||
return map != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
@Override
|
||||
public boolean isReference() {
|
||||
return map == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (map == null) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (map == null) {
|
||||
if (disableLazyLoad) {
|
||||
map = new LinkedHashMap<>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedHashMap<K, E> collectionAdd() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void refresh(ModifyListenMode modifyListenMode, BeanMap<?, ?> newMap) {
|
||||
setModifyListening(modifyListenMode);
|
||||
this.map = (LinkedHashMap<K, E>) newMap.actualMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying map.
|
||||
*/
|
||||
public LinkedHashMap<K, E> actualMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of beans (map values).
|
||||
*/
|
||||
@Override
|
||||
public Collection<E> actualDetails() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map entrySet.
|
||||
*/
|
||||
@Override
|
||||
public Collection<?> actualEntries() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (map == null) {
|
||||
return "BeanMap<deferred>";
|
||||
} else {
|
||||
return map.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if object is a Map and equal in a Map sense.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
init();
|
||||
return map.equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
init();
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyListening) {
|
||||
// add all beans to the removal list
|
||||
for (E bean : map.values()) {
|
||||
modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
init();
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
init();
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (readOnly) {
|
||||
return Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(Object key) {
|
||||
init();
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
init();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
init();
|
||||
if (readOnly) {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E put(K key, E value) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E oldBean = map.put(key, value);
|
||||
if (value != oldBean) {
|
||||
// register the add of the new and the removal of the old
|
||||
modifyAddition(value);
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
return oldBean;
|
||||
} else {
|
||||
return map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends E> puts) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
for (Entry<? extends K, ? extends E> entry : puts.entrySet()) {
|
||||
Object oldBean = map.put(entry.getKey(), entry.getValue());
|
||||
if (entry.getValue() != oldBean) {
|
||||
modifyAddition(entry.getValue());
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map.putAll(puts);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBean(E bean) {
|
||||
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBean(E bean) {
|
||||
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(Object key) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
init();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<E> values() {
|
||||
init();
|
||||
if (readOnly) {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<E> shallowCopy() {
|
||||
BeanMap<K, E> copy = new BeanMap<>(new LinkedHashMap<>(map));
|
||||
copy.setFromOriginal(this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencedMap<K, E> reversed() {
|
||||
init();
|
||||
if (modifyListening) {
|
||||
throw new UnsupportedOperationException("Not supported on modify listening map");
|
||||
}
|
||||
return map.reversed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, E> firstEntry() {
|
||||
init();
|
||||
return map.firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, E> lastEntry() {
|
||||
init();
|
||||
return map.lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, E> pollFirstEntry() {
|
||||
checkReadOnly();
|
||||
init();
|
||||
var entry = map.pollFirstEntry();
|
||||
if (modifyListening && entry != null) {
|
||||
modifyRemoval(entry.getValue());
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, E> pollLastEntry() {
|
||||
checkReadOnly();
|
||||
init();
|
||||
var entry = map.pollLastEntry();
|
||||
if (modifyListening && entry != null) {
|
||||
modifyRemoval(entry.getValue());
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E putFirst(K key, E value) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E oldBean = map.putFirst(key, value);
|
||||
if (value != oldBean) {
|
||||
// register the add of the new and the removal of the old
|
||||
modifyAddition(value);
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
return oldBean;
|
||||
} else {
|
||||
return map.putFirst(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E putLast(K key, E value) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E oldBean = map.putLast(key, value);
|
||||
if (value != oldBean) {
|
||||
// register the add of the new and the removal of the old
|
||||
modifyAddition(value);
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
return oldBean;
|
||||
} else {
|
||||
return map.putLast(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencedSet<K> sequencedKeySet() {
|
||||
init();
|
||||
return map.sequencedKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencedCollection<E> sequencedValues() {
|
||||
init();
|
||||
return map.sequencedValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencedSet<Entry<K, E>> sequencedEntrySet() {
|
||||
init();
|
||||
return map.sequencedEntrySet();
|
||||
}
|
||||
}
|
||||
@@ -1,460 +0,0 @@
|
||||
package io.ebean.common;
|
||||
|
||||
import io.ebean.bean.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.SequencedSet;
|
||||
|
||||
/**
|
||||
* Set capable of lazy loading and modification aware.
|
||||
*/
|
||||
public final class BeanSet<E> extends AbstractBeanCollection<E> implements SequencedSet<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying Set implementation.
|
||||
*/
|
||||
private LinkedHashSet<E> set;
|
||||
|
||||
/**
|
||||
* Create with a specific Set implementation.
|
||||
*/
|
||||
public BeanSet(LinkedHashSet<E> set) {
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using an underlying LinkedHashSet.
|
||||
*/
|
||||
public BeanSet() {
|
||||
this(new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(ToStringBuilder builder) {
|
||||
builder.addCollection(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSkipSave() {
|
||||
return set == null || (set.isEmpty() && !holdsModifications());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addEntityBean(EntityBean bean) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(BeanCollection<?> other) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
set.addAll((Collection<? extends E>) other.actualDetails());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalAddWithCheck(Object bean) {
|
||||
// set add() already de-dups so just add it
|
||||
internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
if (bean != null) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying set has its data.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPopulated() {
|
||||
return set != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
@Override
|
||||
public boolean isReference() {
|
||||
return set == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (set == null) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(false);
|
||||
} else {
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (set == null) {
|
||||
if (disableLazyLoad) {
|
||||
set = new LinkedHashSet<>();
|
||||
} else {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public BeanCollectionAdd collectionAdd() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void refresh(ModifyListenMode modifyListenMode, BeanSet<E> newSet) {
|
||||
setModifyListening(modifyListenMode);
|
||||
this.set = newSet.actualSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying set.
|
||||
*/
|
||||
public LinkedHashSet<E> actualSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<E> actualDetails() {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> actualEntries() {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (set == null) {
|
||||
return "BeanSet<deferred>";
|
||||
} else {
|
||||
return set.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a Set and equal in a Set sense.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return set.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
init();
|
||||
return set.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBean(E bean) {
|
||||
add(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBean(E bean) {
|
||||
if (set.remove(bean)) {
|
||||
getModifyHolder().modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// proxy method for map
|
||||
// -----------------------------------------------------//
|
||||
|
||||
@Override
|
||||
public boolean add(E bean) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
if (set.add(bean)) {
|
||||
modifyAddition(bean);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return set.add(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
boolean changed = false;
|
||||
for (E bean : beans) {
|
||||
if (set.add(bean)) {
|
||||
// register the addition of the bean
|
||||
modifyAddition(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.addAll(beans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyListening) {
|
||||
for (E bean : set) {
|
||||
modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object bean) {
|
||||
init();
|
||||
return set.contains(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> beans) {
|
||||
init();
|
||||
return set.containsAll(beans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
init();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (readOnly) {
|
||||
return new ReadOnlyIterator<>(set.iterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyIterator<>(this, set.iterator());
|
||||
}
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object bean) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
if (set.remove(bean)) {
|
||||
modifyRemoval(bean);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return set.remove(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
boolean changed = false;
|
||||
for (Object bean : beans) {
|
||||
if (set.remove(bean)) {
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.removeAll(beans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object bean = it.next();
|
||||
if (!beans.contains(bean)) {
|
||||
// not retaining this bean so add it to the removal list
|
||||
it.remove();
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.retainAll(beans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
init();
|
||||
return set.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
init();
|
||||
return set.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
init();
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return set.toArray(array);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SequencedSet<E> reversed() {
|
||||
init();
|
||||
if (modifyListening) {
|
||||
throw new UnsupportedOperationException("Not supported on modify listening set");
|
||||
}
|
||||
return set.reversed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFirst(E bean) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
modifyAddition(bean);
|
||||
}
|
||||
set.addFirst(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLast(E bean) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
modifyAddition(bean);
|
||||
}
|
||||
set.addLast(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getFirst() {
|
||||
init();
|
||||
return set.getFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getLast() {
|
||||
init();
|
||||
return set.getLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeFirst() {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
var bean = set.removeFirst();
|
||||
modifyRemoval(bean);
|
||||
return bean;
|
||||
}
|
||||
return set.removeFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeLast() {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
var bean = set.removeLast();
|
||||
modifyRemoval(bean);
|
||||
return bean;
|
||||
}
|
||||
return set.removeLast();
|
||||
}
|
||||
|
||||
private static final class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2577697326745352605L;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
ReadOnlyIterator(Iterator<E> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
return it.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<E> shallowCopy() {
|
||||
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
|
||||
copy.setFromOriginal(this);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@@ -136,13 +136,13 @@ class ToStringBuilderTest {
|
||||
@Test
|
||||
void beanSet_null_empty() {
|
||||
assertThat(toStringFor(new BeanSet<String>(null))).isEqualTo("[]");
|
||||
assertThat(toStringFor(new BeanSet<String>(new LinkedHashSet<>()))).isEqualTo("[]");
|
||||
assertThat(toStringFor(new BeanSet<String>(Collections.emptySet()))).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanMap_null_empty() {
|
||||
assertThat(toStringFor(new BeanMap<String, String>(null))).isEqualTo("{}");
|
||||
assertThat(toStringFor(new BeanMap<String, String>(new LinkedHashMap<>()))).isEqualTo("{}");
|
||||
assertThat(toStringFor(new BeanMap<String, String>(Collections.emptyMap()))).isEqualTo("{}");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,7 +159,7 @@ class ToStringBuilderTest {
|
||||
|
||||
@Test
|
||||
void beanMap_some() {
|
||||
var under = new LinkedHashMap<String, Recurse>();
|
||||
Map<String, Recurse> under = new LinkedHashMap<>();
|
||||
under.put("a", new Recurse(1, "a"));
|
||||
under.put("b", new Recurse(2, "b"));
|
||||
BeanMap<String, Recurse> list = new BeanMap<>(under);
|
||||
|
||||
+26
-26
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -89,25 +89,25 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -125,13 +125,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -155,37 +155,37 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-spring-txn</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<!-- platforms -->
|
||||
@@ -193,79 +193,79 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-clickhouse</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-db2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-h2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-hana</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-mariadb</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-mysql</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-nuodb</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-oracle</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis-types</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-sqlite</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-sqlserver</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
@@ -16,7 +16,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+6
-6
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -22,7 +22,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -46,7 +46,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -159,21 +159,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-sqlserver</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SPI extension to PersistenceContext.
|
||||
@@ -14,4 +17,14 @@ public interface SpiPersistenceContext extends PersistenceContext {
|
||||
*/
|
||||
List<Object> dirtyBeans(SpiBeanTypeManager manager);
|
||||
|
||||
/**
|
||||
* Return all the entities from this persistence context.
|
||||
*/
|
||||
Map<Class<?>, List<EntityBean>> detach();
|
||||
|
||||
/**
|
||||
* Attach all the cached entities into this persistence context.
|
||||
*/
|
||||
void attach(FrozenBeans cachedBeans);
|
||||
|
||||
}
|
||||
|
||||
@@ -654,16 +654,6 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
|
||||
*/
|
||||
ObjectGraphNode parentNode();
|
||||
|
||||
/**
|
||||
* Set that this is a future query that will execute in the background.
|
||||
*/
|
||||
void usingFuture();
|
||||
|
||||
/**
|
||||
* Return true if this is a future query.
|
||||
*/
|
||||
boolean isUsingFuture();
|
||||
|
||||
/**
|
||||
* Return false when this is a lazy load or refresh query for a bean.
|
||||
* <p>
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.api;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
import io.ebean.event.changelog.ChangeSet;
|
||||
import io.ebeaninternal.server.core.PersistDeferredRelationship;
|
||||
@@ -223,6 +224,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
transaction.register(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrozenBeans freezeAndDetach() {
|
||||
return transaction.freezeAndDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(FrozenBeans frozenBeans) {
|
||||
transaction.attach(frozenBeans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return transaction.isReadOnly();
|
||||
|
||||
@@ -23,4 +23,8 @@ public final class ModifyAwareFlag implements ModifyAwareType, Serializable {
|
||||
this.markedDirty = markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object freeze() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,7 @@ package io.ebeaninternal.json;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Modify aware wrapper of a list.
|
||||
@@ -52,6 +47,11 @@ public final class ModifyAwareList<E> implements List<E>, ModifyAwareType, Seria
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<E> freeze() {
|
||||
return Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
return owner.isMarkedDirty();
|
||||
|
||||
@@ -3,11 +3,7 @@ package io.ebeaninternal.json;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Map that is wraps an underlying map for the purpose of detecting changes.
|
||||
@@ -51,6 +47,11 @@ public final class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, S
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> freeze() {
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
return owner.isMarkedDirty();
|
||||
|
||||
@@ -3,10 +3,7 @@ package io.ebeaninternal.json;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of detecting modifications.
|
||||
@@ -33,6 +30,11 @@ public final class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Seriali
|
||||
this.set = underlying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> freeze() {
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
return owner.isMarkedDirty();
|
||||
|
||||
@@ -1273,7 +1273,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@Override
|
||||
public <T> FutureRowCount<T> findFutureCount(SpiQuery<T> query) {
|
||||
SpiQuery<T> copy = query.copy();
|
||||
copy.usingFuture();
|
||||
boolean createdTransaction = false;
|
||||
SpiTransaction transaction = query.transaction();
|
||||
if (transaction == null) {
|
||||
@@ -1292,7 +1291,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@Override
|
||||
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
|
||||
SpiQuery<T> copy = query.copy();
|
||||
copy.usingFuture();
|
||||
boolean createdTransaction = false;
|
||||
SpiTransaction transaction = query.transaction();
|
||||
if (transaction == null) {
|
||||
@@ -1311,7 +1309,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
@Override
|
||||
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
|
||||
SpiQuery<T> spiQuery = query.copy();
|
||||
spiQuery.usingFuture();
|
||||
// FutureList query always run in it's own persistence content
|
||||
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
|
||||
if (!spiQuery.isDisableReadAudit()) {
|
||||
@@ -1654,50 +1651,41 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the bean.
|
||||
*/
|
||||
@Override
|
||||
public void insert(Object bean) {
|
||||
persister.insert(checkEntityBean(bean), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object bean, @Nullable InsertOptions insertOptions) {
|
||||
persister.insert(checkEntityBean(bean), insertOptions, null);
|
||||
insert(bean, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the bean with a transaction.
|
||||
*/
|
||||
@Override
|
||||
public void insert(Object bean, @Nullable Transaction transaction) {
|
||||
persister.insert(checkEntityBean(bean), null, transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object bean, InsertOptions insertOptions, Transaction transaction) {
|
||||
persister.insert(checkEntityBean(bean), insertOptions, transaction);
|
||||
persister.insert(checkEntityBean(bean), transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all beans in the collection.
|
||||
*/
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans) {
|
||||
insertAll(beans, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans, InsertOptions options) {
|
||||
insertAll(beans, options, null);
|
||||
insertAll(beans, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all beans in the collection with a transaction.
|
||||
*/
|
||||
@Override
|
||||
public void insertAll(@Nullable Collection<?> beans, @Nullable Transaction transaction) {
|
||||
insertAll(beans, null, transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(@Nullable Collection<?> beans, InsertOptions options, @Nullable Transaction transaction) {
|
||||
if (beans == null || beans.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
executeInTrans((txn) -> {
|
||||
txn.checkBatchEscalationOnCollection();
|
||||
for (Object bean : beans) {
|
||||
persister.insert(checkEntityBean(bean), options, txn);
|
||||
persister.insert(checkEntityBean(bean), txn);
|
||||
}
|
||||
return 0;
|
||||
}, transaction);
|
||||
|
||||
@@ -35,6 +35,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
private final OrmQueryEngine queryEngine;
|
||||
private final SpiQuery<T> query;
|
||||
private final BeanFindController finder;
|
||||
private final Boolean readOnly;
|
||||
private LoadContext loadContext;
|
||||
private PersistenceContext persistenceContext;
|
||||
private HashQuery cacheKey;
|
||||
@@ -51,6 +52,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
this.finder = beanDescriptor.beanFinder();
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.persistenceContext = query.persistenceContext();
|
||||
}
|
||||
|
||||
@@ -133,6 +135,13 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
return loadContext.secondaryQueriesMinBatchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Normal, sharedInstance, ReadOnly state of this query.
|
||||
*/
|
||||
public Boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.InsertOptions;
|
||||
import io.ebean.ValuePair;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.EntityBean;
|
||||
@@ -125,7 +124,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Many-to-many intersection table changes that are held for later batch processing.
|
||||
*/
|
||||
private List<SaveMany> saveMany;
|
||||
private InsertOptions insertOptions;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, int flags) {
|
||||
@@ -382,14 +380,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return intercept.dirtyPropertyNames();
|
||||
}
|
||||
|
||||
public boolean isChangedProperty(int propertyIndex) {
|
||||
if (dirtyProperties == null) {
|
||||
return intercept.isChangedProperty(propertyIndex);
|
||||
} else {
|
||||
return dirtyProperties[propertyIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the dirty properties on this request.
|
||||
*/
|
||||
@@ -875,8 +865,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
setNotifyCache();
|
||||
boolean isChangeLog = beanDescriptor.isChangeLog();
|
||||
if (type == Type.UPDATE) {
|
||||
// get the dirty properties for notify cache & orphanRemoval of vanilla collection detection
|
||||
if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
|
||||
// get the dirty properties for update notification to the doc store
|
||||
dirtyProperties = intercept.dirtyProperties();
|
||||
}
|
||||
if (isChangeLog) {
|
||||
@@ -1418,12 +1408,4 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
private void setGeneratedId() {
|
||||
beanDescriptor.setGeneratedId(entityBean, transaction);
|
||||
}
|
||||
|
||||
public void setInsertOptions(InsertOptions insertOptions) {
|
||||
this.insertOptions = insertOptions;
|
||||
}
|
||||
|
||||
public InsertOptions insertOptions() {
|
||||
return insertOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.avaje.lang.Nullable;
|
||||
import io.ebean.*;
|
||||
import io.ebean.CallableSql;
|
||||
import io.ebean.MergeOptions;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.Update;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebeaninternal.api.SpiSqlUpdate;
|
||||
@@ -27,9 +31,9 @@ public interface Persister {
|
||||
void update(EntityBean entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Perform an Insert using the given bean.
|
||||
* Force an Insert using the given bean.
|
||||
*/
|
||||
void insert(EntityBean entityBean, @Nullable InsertOptions insertOptions, @Nullable Transaction t);
|
||||
void insert(EntityBean entityBean, Transaction t);
|
||||
|
||||
/**
|
||||
* Insert or update the bean depending on its state.
|
||||
@@ -40,6 +44,7 @@ public interface Persister {
|
||||
* Delete a bean given it's type and id value.
|
||||
* <p>
|
||||
* This will also cascade delete one level of children.
|
||||
* </p>
|
||||
*/
|
||||
int delete(Class<?> beanType, Object id, Transaction transaction, boolean permanent);
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.query.CQueryCollectionAdd;
|
||||
|
||||
@@ -31,7 +34,7 @@ public interface BeanCollectionHelp<T> extends CQueryCollectionAdd<T> {
|
||||
* For Map's this needs to take the mapKey.
|
||||
* </p>
|
||||
*/
|
||||
BeanCollectionAdd collectionAdd(Object bc, String mapKey);
|
||||
BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
|
||||
|
||||
/**
|
||||
* Create an empty collection of the correct type without a parent bean.
|
||||
|
||||
@@ -687,6 +687,16 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
||||
}
|
||||
}
|
||||
|
||||
public void freeze(EntityBean entityBean) {
|
||||
for (BeanProperty beanProperty : propertiesMutable) {
|
||||
beanProperty.freeze(entityBean);
|
||||
}
|
||||
for (BeanPropertyAssocMany<?> many : propertiesMany) {
|
||||
many.freeze(entityBean);
|
||||
}
|
||||
entityBean._ebean_getIntercept().freeze();
|
||||
}
|
||||
|
||||
public void metricPersistBatch(PersistRequest.Type type, long startNanos, int size) {
|
||||
iudMetrics.addBatch(type, startNanos, size);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanList;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -19,11 +23,19 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
|
||||
super(many);
|
||||
}
|
||||
|
||||
BeanListHelp() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
if (bc instanceof BeanList<?>) {
|
||||
BeanList<?> bl = (BeanList<?>) bc;
|
||||
return bl.collectionAdd();
|
||||
if (bl.actualList() == null) {
|
||||
bl.setActualList(new ArrayList<>());
|
||||
}
|
||||
return bl;
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
@@ -55,20 +67,20 @@ public class BeanListHelp<T> extends BaseCollectionHelp<T> {
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
BeanList<T> newBeanList = (BeanList<T>) bc;
|
||||
BeanList<?> newBeanList = (BeanList<?>) bc;
|
||||
List<?> currentList = (List<?>) many.getValue(parentBean);
|
||||
newBeanList.setModifyListening(many.modifyListenMode());
|
||||
if (currentList == null) {
|
||||
// the currentList is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanList);
|
||||
|
||||
} else if (currentList instanceof BeanList) {
|
||||
} else if (currentList instanceof BeanList<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanList<T> currentBeanList = (BeanList<T>) currentList;
|
||||
currentBeanList.refresh(many.modifyListenMode(), newBeanList);
|
||||
BeanList<?> currentBeanList = (BeanList<?>) currentList;
|
||||
currentBeanList.setActualList(newBeanList.actualList());
|
||||
currentBeanList.setModifyListening(many.modifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire list with the BeanList
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanMap;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -33,14 +37,20 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
if (mapKey == null) {
|
||||
mapKey = many.mapKey();
|
||||
}
|
||||
BeanProperty beanProp = targetDescriptor.beanProperty(mapKey);
|
||||
if (bc instanceof BeanMap<?, ?>) {
|
||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
||||
return new Adder(beanProp, bm.collectionAdd());
|
||||
Map<Object, Object> actualMap = bm.actualMap();
|
||||
if (actualMap == null) {
|
||||
actualMap = new LinkedHashMap<>();
|
||||
bm.setActualMap(actualMap);
|
||||
}
|
||||
return new Adder(beanProp, actualMap);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
@@ -116,7 +126,8 @@ public class BeanMapHelp<T> extends BaseCollectionHelp<T> {
|
||||
} else if (current instanceof BeanMap<?, ?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||
currentBeanMap.refresh(many.modifyListenMode(), newBeanMap);
|
||||
currentBeanMap.setActualMap(newBeanMap.actualMap());
|
||||
currentBeanMap.setModifyListening(many.modifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.ModifyAwareType;
|
||||
import io.ebean.ValuePair;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.MutableValueInfo;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.bean.*;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
@@ -1498,4 +1496,15 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
desc.registerColumn(dbColumn, path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Freeze mutable types (like DbArray).
|
||||
*/
|
||||
public void freeze(EntityBean entityBean) {
|
||||
Object value = getValue(entityBean);
|
||||
if (value instanceof ModifyAwareType) {
|
||||
ModifyAwareType bc = (ModifyAwareType) value;
|
||||
setValue(entityBean, bc.freeze());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +655,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
||||
}
|
||||
|
||||
private BeanCollectionAdd beanCollectionAdd(Object bc) {
|
||||
return help.collectionAdd(bc, null);
|
||||
return help.getBeanCollectionAdd(bc, null);
|
||||
}
|
||||
|
||||
public Object parentId(EntityBean parentBean) {
|
||||
@@ -1133,4 +1133,17 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void freeze(EntityBean entityBean) {
|
||||
Object value = getValue(entityBean);
|
||||
if (value instanceof BeanCollection) {
|
||||
BeanCollection<?> bc = (BeanCollection<?>) value;
|
||||
setValue(entityBean, bc.freeze());
|
||||
if (bc.isReference()) {
|
||||
// make it an error to access the collection (no lazy loading allowed)
|
||||
entityBean._ebean_getIntercept().setPropertyUnloaded(propertyIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanSet;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -22,11 +26,21 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
||||
super(many);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a query that returns a set.
|
||||
*/
|
||||
BeanSetHelp() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BeanCollectionAdd collectionAdd(Object bc, String mapKey) {
|
||||
public final BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
if (bc instanceof BeanSet<?>) {
|
||||
BeanSet<?> beanSet = (BeanSet<?>) bc;
|
||||
return beanSet.collectionAdd();
|
||||
if (beanSet.actualSet() == null) {
|
||||
beanSet.setActualSet(new LinkedHashSet<>());
|
||||
}
|
||||
return beanSet;
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
@@ -58,10 +72,9 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
||||
return beanSet;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
BeanSet<T> newBeanSet = (BeanSet<T>) bc;
|
||||
BeanSet<?> newBeanSet = (BeanSet<?>) bc;
|
||||
Set<?> current = (Set<?>) many.getValue(parentBean);
|
||||
newBeanSet.setModifyListening(many.modifyListenMode());
|
||||
if (current == null) {
|
||||
@@ -70,8 +83,9 @@ public class BeanSetHelp<T> extends BaseCollectionHelp<T> {
|
||||
|
||||
} else if (current instanceof BeanSet<?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanSet<T> currentBeanSet = (BeanSet<T>) current;
|
||||
currentBeanSet.refresh(many.modifyListenMode(), newBeanSet);
|
||||
BeanSet<?> currentBeanSet = (BeanSet<?>) current;
|
||||
currentBeanSet.setActualSet(newBeanSet.actualSet());
|
||||
currentBeanSet.setModifyListening(many.modifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanMap;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
final class ElementHelpMap implements ElementHelp {
|
||||
|
||||
@@ -14,7 +15,7 @@ final class ElementHelpMap implements ElementHelp {
|
||||
|
||||
private static class Collector implements ElementCollector {
|
||||
|
||||
private final LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
|
||||
private final Map<Object, Object> map = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
public void addElement(Object element) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanSet;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
final class ElementHelpSet implements ElementHelp {
|
||||
|
||||
@@ -14,7 +15,7 @@ final class ElementHelpSet implements ElementHelp {
|
||||
|
||||
private static class Collector implements ElementCollector {
|
||||
|
||||
private final LinkedHashSet<Object> set = new LinkedHashSet<>();
|
||||
private final Set<Object> set = new LinkedHashSet<>();
|
||||
|
||||
@Override
|
||||
public void addElement(Object element) {
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ public final class DeployCreateProperties {
|
||||
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
|
||||
}
|
||||
// check for Collection type (list, set or map)
|
||||
ManyType manyType = determineManyType.manyType(propertyType);
|
||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
||||
if (manyType != null) {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
|
||||
+3
-3
@@ -11,14 +11,14 @@ import java.util.Set;
|
||||
*/
|
||||
final class DetermineManyType {
|
||||
|
||||
ManyType manyType(Class<?> type) {
|
||||
ManyType getManyType(Class<?> type) {
|
||||
if (type.equals(List.class)) {
|
||||
return ManyType.LIST;
|
||||
}
|
||||
if (type.equals(Set.class) || type.getCanonicalName().equals("java.util.SequencedSet")) {
|
||||
if (type.equals(Set.class)) {
|
||||
return ManyType.SET;
|
||||
}
|
||||
if (type.equals(Map.class) || type.getCanonicalName().equals("java.util.SequencedMap")) {
|
||||
if (type.equals(Map.class)) {
|
||||
return ManyType.MAP;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -411,7 +411,7 @@ public final class DefaultPersister implements Persister {
|
||||
if (bean._ebean_getIntercept().isUpdate()) {
|
||||
update(bean, t);
|
||||
} else {
|
||||
insert(bean, null, t);
|
||||
insert(bean, t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,15 +419,12 @@ public final class DefaultPersister implements Persister {
|
||||
* Insert this bean.
|
||||
*/
|
||||
@Override
|
||||
public void insert(EntityBean bean, InsertOptions insertOptions, Transaction t) {
|
||||
public void insert(EntityBean bean, Transaction t) {
|
||||
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
|
||||
if (req.isSkipReference()) {
|
||||
// skip insert on reference bean
|
||||
return;
|
||||
}
|
||||
if (insertOptions != null) {
|
||||
req.setInsertOptions(insertOptions);
|
||||
}
|
||||
try {
|
||||
req.initTransIfRequiredWithBatchCascade();
|
||||
insert(req);
|
||||
|
||||
@@ -328,7 +328,7 @@ final class SaveManyBeans extends SaveManyBase {
|
||||
}
|
||||
|
||||
private boolean isChangedProperty() {
|
||||
return request.isChangedProperty(many.propertyIndex());
|
||||
return parentBean._ebean_getIntercept().isChangedProperty(many.propertyIndex());
|
||||
}
|
||||
|
||||
private void removeAssocManyOrphans() {
|
||||
|
||||
+1
-9
@@ -1,15 +1,11 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper to support the generation of DML statements.
|
||||
*/
|
||||
public final class GenerateDmlRequest {
|
||||
|
||||
private final StringBuilder sb = new StringBuilder(100);
|
||||
private final List<String> columns = new ArrayList<>();
|
||||
private StringBuilder insertBindBuffer;
|
||||
private String prefix;
|
||||
private String prefix2;
|
||||
@@ -30,7 +26,7 @@ public final class GenerateDmlRequest {
|
||||
++bindColumnCount;
|
||||
sb.append(prefix);
|
||||
sb.append(column);
|
||||
columns.add(column);
|
||||
//sb.append(expr);
|
||||
if (insertMode > 0) {
|
||||
if (insertMode++ > 1) {
|
||||
insertBindBuffer.append(',');
|
||||
@@ -79,8 +75,4 @@ public final class GenerateDmlRequest {
|
||||
public boolean isUpdate() {
|
||||
return insertMode == 0;
|
||||
}
|
||||
|
||||
public List<String> columns() {
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public final class InsertHandler extends DmlHandler {
|
||||
|
||||
SpiTransaction t = persistRequest.transaction();
|
||||
// get the appropriate sql
|
||||
sql = meta.sql(withId, persistRequest.isPublish(), persistRequest.insertOptions());
|
||||
sql = meta.getSql(withId, persistRequest.isPublish());
|
||||
PreparedStatement pstmt;
|
||||
if (persistRequest.isBatched()) {
|
||||
pstmt = pstmtBatch(t, sql, persistRequest, useGeneratedKeys);
|
||||
@@ -134,8 +134,7 @@ public final class InsertHandler extends DmlHandler {
|
||||
if (idValue != null) {
|
||||
persistRequest.setGeneratedKey(idValue);
|
||||
}
|
||||
} else if (persistRequest.insertOptions() == null) {
|
||||
// insert on conflict do nothing can not return generated key
|
||||
} else {
|
||||
throw new PersistenceException("Autoincrement getGeneratedKeys() returned no rows?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import io.ebean.InsertOptions;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -37,11 +36,9 @@ final class InsertMeta {
|
||||
private final Bindable shadowFKey;
|
||||
private final String[] identityDbColumns;
|
||||
private final Platform platform;
|
||||
private final InsertMetaOptions options;
|
||||
|
||||
InsertMeta(DatabasePlatform dbPlatform, BeanDescriptor<?> desc, Bindable shadowFKey, BindableId id, BindableList all) {
|
||||
this.platform = dbPlatform.platform();
|
||||
this.options = InsertMetaPlatform.create(platform, desc, this);
|
||||
this.discriminator = discriminator(desc);
|
||||
this.id = id;
|
||||
this.all = all;
|
||||
@@ -50,8 +47,8 @@ final class InsertMeta {
|
||||
|
||||
String tableName = desc.baseTable();
|
||||
String draftTableName = desc.draftTable();
|
||||
this.sqlWithId = sql(false, tableName, false);
|
||||
this.sqlDraftWithId = desc.isDraftable() ? sql(false, draftTableName, true) : sqlWithId;
|
||||
this.sqlWithId = genSql(false, tableName, false);
|
||||
this.sqlDraftWithId = desc.isDraftable() ? genSql(false, draftTableName, true) : sqlWithId;
|
||||
|
||||
// only available for single Id property
|
||||
if (id.isConcatenated()) {
|
||||
@@ -75,8 +72,8 @@ final class InsertMeta {
|
||||
this.supportsGetGeneratedKeys = dbPlatform.dbIdentity().isSupportsGetGeneratedKeys();
|
||||
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
|
||||
}
|
||||
this.sqlNullId = sql(true, tableName, false);
|
||||
this.sqlDraftNullId = desc.isDraftable() ? sql(true, draftTableName, true) : sqlNullId;
|
||||
this.sqlNullId = genSql(true, tableName, false);
|
||||
this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,20 +137,9 @@ final class InsertMeta {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql for the given options.
|
||||
* get the sql based whether the id value(s) are null.
|
||||
*/
|
||||
public String sql(boolean withId, boolean publish, InsertOptions insertOptions) {
|
||||
if (insertOptions == null) {
|
||||
return sql(withId, publish);
|
||||
}
|
||||
return options.sql(withId, insertOptions);
|
||||
}
|
||||
|
||||
String sqlFor(boolean withId) {
|
||||
return withId ? sqlWithId : sqlNullId;
|
||||
}
|
||||
|
||||
private String sql(boolean withId, boolean publish) {
|
||||
public String getSql(boolean withId, boolean publish) {
|
||||
if (withId) {
|
||||
return publish ? sqlWithId : sqlDraftWithId;
|
||||
} else {
|
||||
@@ -161,18 +147,12 @@ final class InsertMeta {
|
||||
}
|
||||
}
|
||||
|
||||
private String sql(boolean nullId, String table, boolean draftTable) {
|
||||
private String genSql(boolean nullId, String table, boolean draftTable) {
|
||||
GenerateDmlRequest request = new GenerateDmlRequest();
|
||||
sql(request, nullId, table, draftTable);
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
void sql(GenerateDmlRequest request, boolean nullId, String table, boolean draftTable) {
|
||||
request.setInsertSetMode();
|
||||
request.append("insert into ").append(table);
|
||||
if (nullId && noColumnsForInsert(draftTable)) {
|
||||
request.append(defaultValues());
|
||||
return;
|
||||
return request.append(defaultValues()).toString();
|
||||
}
|
||||
request.append(" (");
|
||||
if (!nullId) {
|
||||
@@ -192,6 +172,7 @@ final class InsertMeta {
|
||||
request.append(") values (");
|
||||
request.append(request.insertBindBuffer());
|
||||
request.append(")");
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
private String defaultValues() {
|
||||
@@ -215,4 +196,5 @@ final class InsertMeta {
|
||||
&& discriminator == null
|
||||
&& (draftTable ? all.isEmpty() : allExcludeDraftOnly.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import io.ebean.InsertOptions;
|
||||
|
||||
/**
|
||||
* Generator for insert SQL with options.
|
||||
*/
|
||||
interface InsertMetaOptions {
|
||||
|
||||
/**
|
||||
* Generate the SQL for the given insert options.
|
||||
*/
|
||||
String sql(boolean withId, InsertOptions insertOptions);
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import io.ebean.InsertOptions;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Postgres specific generation of insert on conflict.
|
||||
*/
|
||||
final class InsertMetaOptionsPostgres implements InsertMetaOptions {
|
||||
|
||||
private final InsertMeta meta;
|
||||
private final BeanDescriptor<?> desc;
|
||||
private final String baseTable;
|
||||
private final Map<String, String> sqlCache = new ConcurrentHashMap<>();
|
||||
|
||||
InsertMetaOptionsPostgres(InsertMeta meta, BeanDescriptor<?> desc) {
|
||||
this.meta = meta;
|
||||
this.desc = desc;
|
||||
this.baseTable = desc.baseTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sql(boolean withId, InsertOptions options) {
|
||||
String key = withId + options.key();
|
||||
return sqlCache.computeIfAbsent(key, k -> generate(withId, options));
|
||||
}
|
||||
|
||||
private String generate(boolean withId, InsertOptions options) {
|
||||
char type = options.key().charAt(0);
|
||||
switch (type) {
|
||||
case 'U':
|
||||
return generate(withId, false, options);
|
||||
case 'N':
|
||||
return generate(withId, true, options);
|
||||
default:
|
||||
return meta.sqlFor(withId);
|
||||
}
|
||||
}
|
||||
|
||||
private String generate(boolean withId, boolean doNothing, InsertOptions options) {
|
||||
GenerateDmlRequest request = new GenerateDmlRequest();
|
||||
meta.sql(request, !withId, baseTable, false);
|
||||
request.append(" on conflict ");
|
||||
|
||||
List<String> uniqueColumns = desc.uniqueProps().stream()
|
||||
.flatMap(Arrays::stream)
|
||||
.map(BeanProperty::dbColumn)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
String constraintName = options.constraint();
|
||||
if (constraintName != null) {
|
||||
request.append("on constraint ").append(constraintName);
|
||||
} else {
|
||||
request.append("(");
|
||||
String cols = options.uniqueColumns();
|
||||
if (cols != null) {
|
||||
request.append(cols);
|
||||
} else {
|
||||
appendUniqueColumns(uniqueColumns, request);
|
||||
}
|
||||
request.append(")");
|
||||
}
|
||||
if (doNothing) {
|
||||
request.append(" do nothing");
|
||||
return request.toString();
|
||||
}
|
||||
request.append(" do update set ");
|
||||
String updateSet = options.updateSet();
|
||||
if (updateSet != null) {
|
||||
request.append(updateSet);
|
||||
} else {
|
||||
setColumns(withId, request, uniqueColumns);
|
||||
}
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
private void setColumns(boolean withId, GenerateDmlRequest request, List<String> uniqueColumns) {
|
||||
List<String> columns = request.columns();
|
||||
columns.removeAll(uniqueColumns);
|
||||
if (withId) {
|
||||
BeanProperty idProperty = desc.idProperty();
|
||||
if (idProperty != null && !idProperty.isEmbedded()) {
|
||||
columns.remove(idProperty.dbColumn());
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < columns.size(); i++) {
|
||||
if (i > 0) {
|
||||
request.append(", ");
|
||||
}
|
||||
String col = columns.get(i);
|
||||
request.append(col).append("=excluded.").append(col);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendUniqueColumns(List<String> uniqueColumns, GenerateDmlRequest request) {
|
||||
if (uniqueColumns.isEmpty()) {
|
||||
throw new IllegalStateException("Unable to identify unique columns for INSERT ON CONFLICT - Add mapping like @Column(unique=true) or @Index(unique=true)");
|
||||
}
|
||||
for (int i = 0; i < uniqueColumns.size(); i++) {
|
||||
if (i > 0) {
|
||||
request.append(", ");
|
||||
}
|
||||
request.append(uniqueColumns.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dml;
|
||||
|
||||
import io.ebean.InsertOptions;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
final class InsertMetaPlatform {
|
||||
|
||||
private static final NotSupported NOT_SUPPORTED = new NotSupported();
|
||||
|
||||
static InsertMetaOptions create(Platform platform, BeanDescriptor<?> desc, InsertMeta meta) {
|
||||
switch (platform.base()) {
|
||||
case POSTGRES:
|
||||
case YUGABYTE:
|
||||
case COCKROACH:
|
||||
return new InsertMetaOptionsPostgres(meta, desc);
|
||||
default:
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
static final class NotSupported implements InsertMetaOptions {
|
||||
@Override
|
||||
public String sql(boolean withId, InsertOptions insertOptions) {
|
||||
throw new UnsupportedOperationException("InsertOptions not supported on this database platform");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
|
||||
this.queryMode = query.mode();
|
||||
this.loadContextBean = queryMode.isLoadContextBean() || query.getForUpdateLockType() != null;
|
||||
this.lazyLoadManyProperty = query.lazyLoadMany();
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.readOnly = request.isReadOnly();
|
||||
this.disableLazyLoading = query.isDisableLazyLoading();
|
||||
this.objectGraphNode = query.parentNode();
|
||||
this.profilingListener = query.profilingListener();
|
||||
|
||||
@@ -51,10 +51,6 @@ public final class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
* Flushes the jdbc batch by default unless explicitly turned off on the transaction.
|
||||
*/
|
||||
private <T> void flushJdbcBatchOnQuery(OrmQueryRequest<T> request) {
|
||||
if (request.query().isUsingFuture()) {
|
||||
// future queries never invoke a flush
|
||||
return;
|
||||
}
|
||||
SpiTransaction t = request.transaction();
|
||||
if (t.isFlushOnQuery()) {
|
||||
// before we perform a query, we need to flush any
|
||||
|
||||
@@ -31,7 +31,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
|
||||
final boolean readId;
|
||||
private final boolean readIdNormal;
|
||||
private final boolean disableLazyLoad;
|
||||
private final boolean readOnlyNoIntercept;
|
||||
private final boolean readOnly;
|
||||
private final InheritInfo inheritInfo;
|
||||
final String prefix;
|
||||
private final Map<String, String> pathMap;
|
||||
@@ -54,7 +54,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
|
||||
this.readId = node.readId;
|
||||
this.readIdNormal = readId && !temporalVersions;
|
||||
this.disableLazyLoad = node.disableLazyLoad;
|
||||
this.readOnlyNoIntercept = disableLazyLoad && node.readOnly;
|
||||
this.readOnly = node.readOnly;
|
||||
this.partialObject = node.partialObject;
|
||||
this.properties = node.properties;
|
||||
this.pathMap = node.pathMap;
|
||||
@@ -162,7 +162,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
|
||||
|
||||
void initBeanType() throws SQLException {
|
||||
localDesc = desc;
|
||||
localBean = desc.createEntityBean2(readOnlyNoIntercept);
|
||||
localBean = desc.createEntityBean2(readOnly);
|
||||
localIdBinder = idBinder;
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
|
||||
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
|
||||
for (STreePropertyAssocMany many : localDesc.propsMany()) {
|
||||
if (many != loadingChildProperty) {
|
||||
if (readOnlyNoIntercept) {
|
||||
if (disableLazyLoad && readOnly) {
|
||||
many.createEmptyReference(localBean);
|
||||
} else {
|
||||
// create a proxy for the many (deferred fetching)
|
||||
|
||||
@@ -58,7 +58,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
private Type type;
|
||||
private String label;
|
||||
private Mode mode = Mode.NORMAL;
|
||||
private boolean usingFuture;
|
||||
private Object tenantId;
|
||||
/**
|
||||
* Holds query in structured form.
|
||||
@@ -972,16 +971,6 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void usingFuture() {
|
||||
this.usingFuture = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isUsingFuture() {
|
||||
return usingFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isUsageProfiling() {
|
||||
return usageProfiling;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
final class DFrozenBeans implements FrozenBeans {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Map<Class<?>, Map<Object, EntityBean>> beans;
|
||||
|
||||
DFrozenBeans(Map<Class<?>, Map<Object, EntityBean>> beans) {
|
||||
this.beans = Collections.unmodifiableMap(beans);
|
||||
}
|
||||
|
||||
Set<Map.Entry<Class<?>, Map<Object, EntityBean>>> entries() {
|
||||
return beans.entrySet();
|
||||
}
|
||||
}
|
||||
+45
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.api.SpiBeanType;
|
||||
import io.ebeaninternal.api.SpiBeanTypeManager;
|
||||
@@ -44,6 +45,33 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
|
||||
public DefaultPersistenceContext() {
|
||||
}
|
||||
|
||||
public void attach(FrozenBeans other) {
|
||||
lock.lock();
|
||||
try {
|
||||
DFrozenBeans otherContext = (DFrozenBeans) other;
|
||||
for (Map.Entry<Class<?>, Map<Object, EntityBean>> entry : otherContext.entries()) {
|
||||
classContext(entry.getKey()).attach(entry.getValue());
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Class<?>, List<EntityBean>> detach() {
|
||||
lock.lock();
|
||||
try {
|
||||
expungeStaleEntries();
|
||||
Map<Class<?>, List<EntityBean>> result = new LinkedHashMap<>();
|
||||
for (Map.Entry<Class<?>, ClassContext> entry : typeCache.entrySet()) {
|
||||
result.put(entry.getKey(), entry.getValue().beans());
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginIterate() {
|
||||
lock.lock();
|
||||
@@ -247,6 +275,23 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
|
||||
return "size:" + map.size() + " (" + weakCount + " weak)";
|
||||
}
|
||||
|
||||
List<EntityBean> beans() {
|
||||
List<EntityBean> beans = new ArrayList<>(map.size());
|
||||
for (Object value : map.values()) {
|
||||
if (value instanceof BeanRef) {
|
||||
value = ((BeanRef) value).get();
|
||||
}
|
||||
if (value != null) {
|
||||
beans.add((EntityBean) value);
|
||||
}
|
||||
}
|
||||
return beans;
|
||||
}
|
||||
|
||||
void attach(Map<Object, EntityBean> value) {
|
||||
map.putAll(value);
|
||||
}
|
||||
|
||||
private Object get(Object id) {
|
||||
Object ret = map.get(id);
|
||||
if (ret instanceof BeanRef) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.transaction;
|
||||
import io.ebean.ProfileLocation;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
import io.ebean.event.changelog.ChangeSet;
|
||||
@@ -130,6 +131,16 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrozenBeans freezeAndDetach() {
|
||||
return manager.freezeAndDetach(persistenceContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(FrozenBeans frozenBeans) {
|
||||
persistenceContext.attach(frozenBeans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setLabel(String label) {
|
||||
this.label = label;
|
||||
|
||||
@@ -6,6 +6,8 @@ import io.ebean.ProfileLocation;
|
||||
import io.ebean.TxScope;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxType;
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.cache.ServerCacheNotification;
|
||||
import io.ebean.cache.ServerCacheNotify;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
@@ -22,6 +24,7 @@ import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import io.ebeaninternal.server.cache.CacheChangeSet;
|
||||
import io.ebeaninternal.server.cluster.ClusterManager;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.profile.TimedProfileLocation;
|
||||
import io.ebeaninternal.server.profile.TimedProfileLocationRegistry;
|
||||
@@ -33,7 +36,9 @@ import jakarta.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -637,4 +642,21 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
}
|
||||
}
|
||||
|
||||
public FrozenBeans freezeAndDetach(SpiPersistenceContext persistenceContext) {
|
||||
Map<Class<?>, Map<Object, EntityBean>> allBeans = new HashMap<>();
|
||||
for (Map.Entry<Class<?>, List<EntityBean>> entry : persistenceContext.detach().entrySet()) {
|
||||
allBeans.put(entry.getKey(), freezeBeanMap(entry));
|
||||
}
|
||||
return new DFrozenBeans(allBeans);
|
||||
}
|
||||
|
||||
private Map<Object, EntityBean> freezeBeanMap(Map.Entry<Class<?>, List<EntityBean>> entry) {
|
||||
BeanDescriptor<?> descriptor = beanDescriptorManager.descriptor(entry.getKey());
|
||||
Map<Object, EntityBean> beanMap = new HashMap<>();
|
||||
for (EntityBean entityBean : entry.getValue()) {
|
||||
descriptor.freeze(entityBean);
|
||||
beanMap.put(descriptor.getId(entityBean), entityBean);
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
public interface ModifyAwareType {
|
||||
|
||||
boolean isDirty();
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean ddl generation</name>
|
||||
@@ -28,14 +28,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean postgis types</name>
|
||||
@@ -19,14 +19,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-postgres</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean querybean</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -63,14 +63,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
@@ -22,28 +22,28 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-spring-txn</artifactId>
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean test</name>
|
||||
@@ -33,20 +33,20 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -149,14 +149,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-jackson-mapper</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-all</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebean.xtest.common;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanList;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Product;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@@ -14,22 +13,22 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class BeanListTest {
|
||||
|
||||
private final Product object1 = new Product(1);
|
||||
private final Product object2 = new Product(2);
|
||||
private final Product object3 = new Product(3);
|
||||
private final Object object1 = new Object();
|
||||
private final Object object2 = new Object();
|
||||
private final Object object3 = new Object();
|
||||
|
||||
private List<Object> all() {
|
||||
List<Object> all = new ArrayList<>();
|
||||
all.add(new Product(1));
|
||||
all.add(new Product(2));
|
||||
all.add(new Product(3));
|
||||
all.add(object1);
|
||||
all.add(object2);
|
||||
all.add(object3);
|
||||
return all;
|
||||
}
|
||||
|
||||
private List<Object> some() {
|
||||
List<Object> some = new ArrayList<>();
|
||||
some.add(new Product(2));
|
||||
some.add(new Product(3));
|
||||
some.add(object2);
|
||||
some.add(object3);
|
||||
return some;
|
||||
}
|
||||
|
||||
@@ -164,15 +163,14 @@ public class BeanListTest {
|
||||
@Test
|
||||
public void testRemove_given_beansInAdditions() {
|
||||
|
||||
List<Object> all = all();
|
||||
BeanList<Object> list = new BeanList<>();
|
||||
list.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
list.addAll(all);
|
||||
list.addAll(all());
|
||||
assertThat(list.modifyAdditions()).containsOnly(object1, object2, object3);
|
||||
|
||||
// act
|
||||
list.remove(all.get(1));
|
||||
list.remove(all.get(2));
|
||||
list.remove(object2);
|
||||
list.remove(object3);
|
||||
|
||||
assertThat(list.modifyAdditions()).containsOnly(object1);
|
||||
assertThat(list.modifyRemovals()).isEmpty();
|
||||
@@ -181,14 +179,13 @@ public class BeanListTest {
|
||||
@Test
|
||||
public void testRemoveAll_given_beansInAdditions() {
|
||||
|
||||
List<Object> all = all();
|
||||
BeanList<Object> list = new BeanList<>();
|
||||
list.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
list.addAll(all);
|
||||
list.addAll(all());
|
||||
assertThat(list.modifyAdditions()).containsOnly(object1, object2, object3);
|
||||
|
||||
// act
|
||||
list.removeAll(List.of(all.get(1), all.get(2)));
|
||||
list.removeAll(some());
|
||||
|
||||
assertThat(list.modifyAdditions()).containsOnly(object1);
|
||||
assertThat(list.modifyRemovals()).isEmpty();
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.ebean.xtest.common;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanMap;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Product;
|
||||
import org.tests.model.basic.EBasic;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -14,24 +14,24 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class BeanMapTest {
|
||||
|
||||
private final Product object1 = new Product(1);
|
||||
private final Product object2 = new Product(2);
|
||||
private final Product object3 = new Product(3);
|
||||
private final Product object4 = new Product(4);
|
||||
private final Product object5 = new Product(5);
|
||||
private final EBasic object1 = new EBasic("o1");
|
||||
private final EBasic object2 = new EBasic("o2");
|
||||
private final EBasic object3 = new EBasic("o3");
|
||||
private final EBasic object4 = new EBasic("o4");
|
||||
private final EBasic object5 = new EBasic("o5");
|
||||
|
||||
private Map<String, Object> all() {
|
||||
Map<String, Object> all = new LinkedHashMap<>();
|
||||
all.put("1", new Product(1));
|
||||
all.put("2", new Product(2));
|
||||
all.put("3", new Product(3));
|
||||
all.put("1", object1);
|
||||
all.put("2", object2);
|
||||
all.put("3", object3);
|
||||
return all;
|
||||
}
|
||||
|
||||
private Map<String, Object> some() {
|
||||
Map<String, Object> all = new LinkedHashMap<>();
|
||||
all.put("2", new Product(2));
|
||||
all.put("3", new Product(3));
|
||||
all.put("2", object2);
|
||||
all.put("3", object3);
|
||||
return all;
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void testAdd_given_someAlreadyIn() {
|
||||
Map<String, Object> some = new LinkedHashMap<>(Map.of("2", object2, "3", object3));
|
||||
BeanMap<String, Object> map = new BeanMap<>(some);
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>(some());
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
// act
|
||||
@@ -90,13 +90,11 @@ public class BeanMapTest {
|
||||
@Test
|
||||
public void testAddSome_given_someAlreadyIn() {
|
||||
|
||||
Map<String, Object> some = new LinkedHashMap<>(Map.of("2", object2, "3", object3));
|
||||
BeanMap<String, Object> map = new BeanMap<>(some);
|
||||
BeanMap<String, Object> map = new BeanMap<>(some());
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
// act
|
||||
Map<String, Object> all = Map.of("1", object1, "2", object2, "3", object3);
|
||||
map.putAll(all);
|
||||
map.putAll(all());
|
||||
|
||||
assertThat(map.modifyAdditions()).containsOnly(object1);
|
||||
assertThat(map.modifyRemovals()).isEmpty();
|
||||
@@ -181,7 +179,7 @@ public class BeanMapTest {
|
||||
@Test
|
||||
public void testClear_given_someBeansInAdditions() {
|
||||
|
||||
BeanMap<String, Product> map = newModifyListeningMap();
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
|
||||
@@ -195,7 +193,7 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void keySet_add_whenModifyListening() {
|
||||
BeanMap<String, Product> map = newModifyListeningMap();
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
assertThrows(UnsupportedOperationException.class, () -> map.keySet().add("3"));
|
||||
}
|
||||
|
||||
@@ -207,7 +205,7 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void keySet_addAll_whenModifyListening() {
|
||||
BeanMap<String, Product> map = newModifyListeningMap();
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
assertThrows(UnsupportedOperationException.class, () -> map.keySet().addAll(asList("3", "4")));
|
||||
}
|
||||
|
||||
@@ -319,13 +317,13 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void values_add() {
|
||||
BeanMap<String, Product> map = new BeanMap<>();
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
assertThrows(UnsupportedOperationException.class, () -> map.values().add(object3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void values_addAll() {
|
||||
BeanMap<String, Product> map = new BeanMap<>();
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
assertThrows(UnsupportedOperationException.class, () -> map.values().addAll(asList(object3, object5)));
|
||||
}
|
||||
|
||||
@@ -339,8 +337,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_clear() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
entries.clear();
|
||||
|
||||
assertThat(entries).isEmpty();
|
||||
@@ -350,8 +348,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_remove() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
assertThat(map).hasSize(5);
|
||||
|
||||
@@ -367,8 +365,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_remove_whenNotEqualValue() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
assertThat(map).hasSize(5);
|
||||
|
||||
@@ -381,11 +379,11 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_iterator_remove() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final Iterator<Map.Entry<String, Product>> iterator = entries.iterator();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
final Iterator<Map.Entry<String, EBasic>> iterator = entries.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, Product> entry = iterator.next();
|
||||
final Map.Entry<String, EBasic> entry = iterator.next();
|
||||
if (entry.getKey().equals("2") || entry.getKey().equals("5")) {
|
||||
iterator.remove();
|
||||
}
|
||||
@@ -397,8 +395,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_removeAll() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
entries.removeAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4)));
|
||||
assertThat(map).hasSize(3);
|
||||
@@ -408,8 +406,8 @@ public class BeanMapTest {
|
||||
|
||||
@Test
|
||||
public void entrySet_retainAll() {
|
||||
final BeanMap<String, Product> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, Product>> entries = map.entrySet();
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
entries.retainAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4)));
|
||||
assertThat(map).hasSize(2);
|
||||
@@ -417,15 +415,15 @@ public class BeanMapTest {
|
||||
assertThat(map.modifyRemovals()).containsOnly(object2, object3, object5);
|
||||
}
|
||||
|
||||
private BeanMap<String, Product> newModifyListeningMap() {
|
||||
BeanMap<String, Product> map = new BeanMap<>();
|
||||
private BeanMap<String, EBasic> newModifyListeningMap() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
return map;
|
||||
}
|
||||
|
||||
private BeanMap<String, Product> newModifyListeningMap5() {
|
||||
BeanMap<String, Product> map = new BeanMap<>();
|
||||
private BeanMap<String, EBasic> newModifyListeningMap5() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.ebean.xtest.common;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Product;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
@@ -13,22 +12,22 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class BeanSetTest {
|
||||
|
||||
Product object1 = new Product(1);
|
||||
Product object2 = new Product(2);
|
||||
Product object3 = new Product(3);
|
||||
Object object1 = new Object();
|
||||
Object object2 = new Object();
|
||||
Object object3 = new Object();
|
||||
|
||||
private Set<Object> all() {
|
||||
Set<Object> all = new LinkedHashSet<>();
|
||||
all.add(new Product(1));
|
||||
all.add(new Product(2));
|
||||
all.add(new Product(3));
|
||||
all.add(object1);
|
||||
all.add(object2);
|
||||
all.add(object3);
|
||||
return all;
|
||||
}
|
||||
|
||||
private Set<Object> some() {
|
||||
Set<Object> some = new LinkedHashSet<>();
|
||||
some.add(new Product(2));
|
||||
some.add(new Product(3));
|
||||
some.add(object2);
|
||||
some.add(object3);
|
||||
return some;
|
||||
}
|
||||
|
||||
@@ -100,9 +99,7 @@ public class BeanSetTest {
|
||||
|
||||
BeanSet<Object> set = new BeanSet<>();
|
||||
set.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
Set<Object> all = Set.of(object1, object2, object3);
|
||||
set.addAll(all);
|
||||
set.addAll(all());
|
||||
assertThat(set.modifyAdditions()).containsOnly(object1, object2, object3);
|
||||
|
||||
// act
|
||||
@@ -118,13 +115,11 @@ public class BeanSetTest {
|
||||
|
||||
BeanSet<Object> set = new BeanSet<>();
|
||||
set.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
Set<Object> all = Set.of(object1, object2, object3);
|
||||
set.addAll(all);
|
||||
set.addAll(all());
|
||||
assertThat(set.modifyAdditions()).containsOnly(object1, object2, object3);
|
||||
|
||||
// act
|
||||
set.removeAll(Set.of(object2, object3));
|
||||
set.removeAll(some());
|
||||
|
||||
assertThat(set.modifyAdditions()).containsOnly(object1);
|
||||
assertThat(set.modifyRemovals()).isEmpty();
|
||||
|
||||
@@ -453,41 +453,21 @@ public class TDSpiServer implements SpiServer {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object bean, InsertOptions insertOptions) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object bean, Transaction transaction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object bean, InsertOptions insertOptions, Transaction transaction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans, InsertOptions options) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans, Transaction transaction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(Collection<?> beans, InsertOptions options, Transaction transaction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(SqlUpdate updSql, Transaction transaction) {
|
||||
return 0;
|
||||
|
||||
@@ -27,14 +27,14 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
try (final Transaction transaction = DB.beginTransaction()) {
|
||||
query = DB.find(Customer.class)
|
||||
.forUpdate()
|
||||
.orderBy().desc("id");
|
||||
.order().desc("id");
|
||||
|
||||
query.findList();
|
||||
}
|
||||
|
||||
if (isSqlServer()) {
|
||||
assertThat(sqlOf(query)).contains("with (updlock)");
|
||||
} else {
|
||||
} else if (!isDb2()){
|
||||
assertThat(sqlOf(query)).contains("for update");
|
||||
}
|
||||
}
|
||||
@@ -48,21 +48,21 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
query = DB.find(Customer.class)
|
||||
.forUpdate()
|
||||
.setMaxRows(3)
|
||||
.orderBy().desc("id");
|
||||
.order().desc("id");
|
||||
|
||||
query.findList();
|
||||
}
|
||||
|
||||
if (isSqlServer()) {
|
||||
assertThat(sqlOf(query)).contains("with (updlock)");
|
||||
} else if (!isOracle()) {
|
||||
} else if (!isOracle() && !isDb2()) {
|
||||
// Oracle does not support FOR UPDATE with FETCH
|
||||
assertThat(sqlOf(query)).contains("for update");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
|
||||
public void testForUpdate_when_alreadyInPCAsReference() {
|
||||
ResetBasicData.reset();
|
||||
Order o0 = DB.find(Order.class).orderBy("id").setMaxRows(1).findOne();
|
||||
@@ -96,7 +96,7 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
|
||||
public void testForUpdate_when_alreadyInPCAsReference_usingLock() {
|
||||
ResetBasicData.reset();
|
||||
Order o0 = DB.find(Order.class).orderBy("id").setMaxRows(1).findOne();
|
||||
@@ -131,7 +131,7 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
|
||||
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
|
||||
public void testForUpdate_when_alreadyInPC() {
|
||||
|
||||
EBasic basic = new EBasic("initialValue");
|
||||
@@ -193,7 +193,7 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
|
||||
Query<Customer> query = DB.find(Customer.class)
|
||||
.forUpdateNoWait()
|
||||
.orderBy().desc("id");
|
||||
.order().desc("id");
|
||||
|
||||
query.findList();
|
||||
if (isOracle()) {
|
||||
@@ -219,7 +219,7 @@ public class TestQueryForUpdate extends BaseTestCase {
|
||||
Query<Customer> query = DB.find(Customer.class)
|
||||
.forUpdateNoWait()
|
||||
.setMaxRows(1)
|
||||
.orderBy().desc("id");
|
||||
.order().desc("id");
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
Customer first = list.get(0);
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
package org.tests.insert;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.InsertOptions;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.test.LoggedSql;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import io.ebean.xtest.ForPlatform;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.update.EPersonOnline;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.ebean.InsertOptions.ON_CONFLICT_NOTHING;
|
||||
import static io.ebean.InsertOptions.ON_CONFLICT_UPDATE;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TestInsertOnConflict extends BaseTestCase {
|
||||
|
||||
InsertOptions onConflictDoUpdateAndGetGeneratedKeys = InsertOptions.builder()
|
||||
.onConflictUpdate()
|
||||
.getGeneratedKeys(true)
|
||||
.build();
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertOnConflictUpdateExplicitTransaction() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a@b.com");
|
||||
|
||||
try (Transaction txn = DB.createTransaction()) {
|
||||
db.insert(bean, ON_CONFLICT_UPDATE, txn);
|
||||
txn.commit();
|
||||
}
|
||||
assertThat(bean.getId()).isNotNull();
|
||||
|
||||
var bean2 = newBean("a@b.com");
|
||||
bean2.setOnlineStatus(false);
|
||||
try (Transaction txn = DB.createTransaction()) {
|
||||
db.insert(bean2, ON_CONFLICT_UPDATE, txn);
|
||||
txn.commit();
|
||||
}
|
||||
assertThat(bean2.getId()).isEqualTo(bean.getId());
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).findList();
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0).getWhenUpdated()).isEqualTo(bean2.getWhenUpdated());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertOnConflictUpdate_when_noIdValue() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a@b.com");
|
||||
db.insert(bean, onConflictDoUpdateAndGetGeneratedKeys);
|
||||
assertThat(bean.getId()).isNotNull();
|
||||
|
||||
var bean2 = newBean("a@b.com");
|
||||
bean2.setOnlineStatus(false);
|
||||
db.insert(bean2, onConflictDoUpdateAndGetGeneratedKeys);
|
||||
assertThat(bean2.getId()).isEqualTo(bean.getId());
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).findList();
|
||||
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0).getWhenUpdated()).isEqualTo(bean2.getWhenUpdated());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertOnConflictUpdate_when_idValueSupplied() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a@b.com");
|
||||
bean.setId(40_042L);
|
||||
db.insert(bean, ON_CONFLICT_UPDATE);
|
||||
assertThat(bean.getId()).isNotNull();
|
||||
|
||||
var bean2 = newBean("a@b.com");
|
||||
bean2.setId(40_043L); // not expected but can be different
|
||||
bean2.setOnlineStatus(false);
|
||||
|
||||
db.insert(bean2, onConflictDoUpdateAndGetGeneratedKeys);
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (id, email, online_status, when_updated) values (?,?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains("insert into e_person_online (id, email, online_status, when_updated) values (?,?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).findList();
|
||||
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0).getWhenUpdated()).isEqualTo(bean2.getWhenUpdated());
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertAll_onConflictUpdate_when_noIdValue() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a1@b.com");
|
||||
var bean2 = newBean("a2@b.com");
|
||||
var bean3 = newBean("a3@b.com");
|
||||
db.insertAll(List.of(bean, bean2, bean3), ON_CONFLICT_UPDATE);
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- bind");
|
||||
assertThat(sql.get(4)).contains(" -- executeBatch()");
|
||||
|
||||
var bean4 = newBean("a1@b.com");
|
||||
var bean5 = newBean("a5@b.com");
|
||||
db.insertAll(List.of(bean4, bean5), ON_CONFLICT_UPDATE);
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).orderBy("id").findList();
|
||||
assertThat(list).hasSize(4);
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertAll_onConflictUpdate_explicitTransaction() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
try (Transaction txn = DB.createTransaction()) {
|
||||
txn.setBatchSize(3);
|
||||
var bean = newBean("a1@b.com");
|
||||
var bean2 = newBean("a2@b.com");
|
||||
var bean3 = newBean("a3@b.com");
|
||||
var bean4 = newBean("a4@b.com");
|
||||
db.insertAll(List.of(bean, bean2, bean3, bean4), ON_CONFLICT_UPDATE, txn);
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(8);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- bind");
|
||||
assertThat(sql.get(4)).contains(" -- executeBatch()");
|
||||
assertThat(sql.get(5)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(6)).contains(" -- bind");
|
||||
assertThat(sql.get(7)).contains(" -- executeBatch()");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).orderBy("id").findList();
|
||||
assertThat(list).hasSize(4);
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void explicitConstraint() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a1@b.com");
|
||||
var bean2 = newBean("a2@b.com");
|
||||
var bean3 = newBean("a3@b.com");
|
||||
|
||||
var ON_CONFLICT_ = InsertOptions.builder()
|
||||
.onConflictUpdate()
|
||||
.constraint("uq_e_person_online_email")
|
||||
.build();
|
||||
|
||||
db.insertAll(List.of(bean, bean2, bean3), ON_CONFLICT_);
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict on constraint uq_e_person_online_email do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- bind");
|
||||
assertThat(sql.get(4)).contains(" -- executeBatch()");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).orderBy("id").findList();
|
||||
assertThat(list).hasSize(3);
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void explicitUniqueColumns() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a1@b.com");
|
||||
var bean2 = newBean("a2@b.com");
|
||||
var bean3 = newBean("a3@b.com");
|
||||
|
||||
var ON_CONFLICT_ = InsertOptions.builder()
|
||||
.onConflictUpdate()
|
||||
.uniqueColumns(" email ")
|
||||
.build();
|
||||
|
||||
db.insertAll(List.of(bean, bean2, bean3), ON_CONFLICT_);
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict ( email ) do update set online_status=excluded.online_status, when_updated=excluded.when_updated");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- bind");
|
||||
assertThat(sql.get(4)).contains(" -- executeBatch()");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).orderBy("id").findList();
|
||||
assertThat(list).hasSize(3);
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void explicitUpdateSet() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a1@b.com");
|
||||
var bean2 = newBean("a2@b.com");
|
||||
|
||||
var ON_CONFLICT_ = InsertOptions.builder()
|
||||
.onConflictUpdate()
|
||||
.updateSet("when_updated=excluded.when_updated, online_status=true")
|
||||
.build();
|
||||
|
||||
db.insertAll(List.of(bean, bean2), ON_CONFLICT_);
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(4);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do update set when_updated=excluded.when_updated, online_status=true");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- executeBatch()");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).orderBy("id").findList();
|
||||
assertThat(list).hasSize(2);
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
|
||||
@Test
|
||||
void insertOnConflictNothing_when_noIdValue() {
|
||||
Database db = DB.getDefault();
|
||||
db.truncate(EPersonOnline.class);
|
||||
LoggedSql.start();
|
||||
|
||||
var bean = newBean("a@b.com");
|
||||
db.insert(bean, ON_CONFLICT_NOTHING);
|
||||
assertThat(bean.getId()).isNotNull();
|
||||
|
||||
var bean2 = newBean("a@b.com");
|
||||
bean2.setOnlineStatus(false);
|
||||
db.insert(bean2, ON_CONFLICT_NOTHING);
|
||||
assertThat(bean2.getId()).isNull();
|
||||
|
||||
var sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do nothing");
|
||||
assertThat(sql.get(1)).contains("insert into e_person_online (email, online_status, when_updated) values (?,?,?) on conflict (email) do nothing");
|
||||
|
||||
List<EPersonOnline> list = db.find(EPersonOnline.class).findList();
|
||||
|
||||
assertThat(list).hasSize(1);
|
||||
assertThat(list.get(0).getWhenUpdated()).isEqualTo(bean.getWhenUpdated());
|
||||
}
|
||||
|
||||
private static EPersonOnline newBean(String email) {
|
||||
EPersonOnline bean = new EPersonOnline();
|
||||
bean.setEmail(email);
|
||||
bean.setOnlineStatus(true);
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,6 @@ public class Product implements Serializable {
|
||||
@Version
|
||||
Timestamp updtime;
|
||||
|
||||
public Product(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Product() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return id.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,11 @@ public class PlainBeanDirtyAware implements ModifyAwareType {
|
||||
return markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object freeze() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
this.markedDirty = markedDirty;
|
||||
|
||||
@@ -28,11 +28,6 @@ public class OmBeanListChild extends Model {
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public OmBeanListChild setId(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,14 +2,10 @@ package org.tests.model.orphanremoval;
|
||||
|
||||
import io.ebean.Model;
|
||||
|
||||
import io.ebean.annotation.WhenCreated;
|
||||
import io.ebean.annotation.WhenModified;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Version;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import static jakarta.persistence.CascadeType.ALL;
|
||||
@@ -23,13 +19,6 @@ public class OmBeanListParent extends Model {
|
||||
@Version
|
||||
private long version;
|
||||
|
||||
private String name;
|
||||
|
||||
@WhenCreated
|
||||
private Instant whenCreated;
|
||||
@WhenModified
|
||||
private Instant whenModified;
|
||||
|
||||
@OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true)
|
||||
private List<OmBeanListChild> children;
|
||||
|
||||
@@ -46,42 +35,6 @@ public class OmBeanListParent extends Model {
|
||||
this.children.clear();
|
||||
this.children.addAll(children);
|
||||
}
|
||||
|
||||
public void setChildren2(List<OmBeanListChild> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Instant getWhenModified() {
|
||||
return whenModified;
|
||||
}
|
||||
|
||||
public void setWhenModified(Instant whenModified) {
|
||||
this.whenModified = whenModified;
|
||||
}
|
||||
|
||||
public Instant getWhenCreated() {
|
||||
return whenCreated;
|
||||
}
|
||||
|
||||
public void setWhenCreated(Instant whenCreated) {
|
||||
this.whenCreated = whenCreated;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-44
@@ -1,20 +1,17 @@
|
||||
package org.tests.model.orphanremoval;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.test.LoggedSql;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
class TestOrphanRemovalOverwrite {
|
||||
public class TestOrphanRemovalOverwrite {
|
||||
|
||||
@Test
|
||||
void testOverwritingMapping() {
|
||||
public void testOverwritingMapping() {
|
||||
OmBeanListParent parent = new OmBeanListParent();
|
||||
parent.save();
|
||||
|
||||
@@ -32,45 +29,8 @@ class TestOrphanRemovalOverwrite {
|
||||
// Refreshing here generates new objects for the associated children that are referred to by the parent.
|
||||
parent.refresh();
|
||||
|
||||
OmBeanListChild child = childList.get(0);
|
||||
assertNotNull(child.getId());
|
||||
|
||||
OmBeanListChild refreshedChild = parent.getChildren().get(0);
|
||||
assertEquals(child.getId(), refreshedChild.getId());
|
||||
assertEquals(child, refreshedChild);
|
||||
assertNotNull(childList.get(0).getId());
|
||||
assertEquals(childList.get(0).getId(), parent.getChildren().get(0).getId());
|
||||
assertEquals(childList, parent.getChildren());
|
||||
}
|
||||
|
||||
@Test
|
||||
void clearAddAll() {
|
||||
OmBeanListChild c1 = new OmBeanListChild("c1");
|
||||
OmBeanListChild c2 = new OmBeanListChild("c2");
|
||||
|
||||
OmBeanListParent parent = new OmBeanListParent();
|
||||
parent.getChildren().add(c1);
|
||||
parent.getChildren().add(c2);
|
||||
parent.save();
|
||||
|
||||
|
||||
OmBeanListChild c3 = new OmBeanListChild("c3");
|
||||
c3.setId(c1.getId());
|
||||
|
||||
OmBeanListParent p1 = DB.find(OmBeanListParent.class, parent.getId());
|
||||
List<OmBeanListChild> children = p1.getChildren();
|
||||
children.clear();
|
||||
children.add(c3);
|
||||
|
||||
LoggedSql.start();
|
||||
DB.save(p1);
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(7);
|
||||
assertThat(sql.get(0)).contains("delete from om_bean_list_child where id=?");
|
||||
assertThat(sql.get(1)).contains(" -- bind");
|
||||
assertThat(sql.get(2)).contains(" -- bind");
|
||||
assertThat(sql.get(3)).contains(" -- executeBatch()");
|
||||
assertThat(sql.get(4)).contains(" insert into om_bean_list_child");
|
||||
assertThat(sql.get(5)).contains(" -- bind");
|
||||
assertThat(sql.get(6)).contains(" -- executeBatch()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
package org.tests.o2m;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.orphanremoval.OmBeanListChild;
|
||||
import org.tests.model.orphanremoval.OmBeanListParent;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OneToManyListMarkAsDirtyTest extends BaseTestCase {
|
||||
@Test
|
||||
void usingNewListWithNonDirtyParent_expect_orphanDeleted_works() {
|
||||
// setup
|
||||
var parent = new OmBeanListParent();
|
||||
var a_b = new OmBeanListChild("b");
|
||||
parent.getChildren().add(a_b);
|
||||
DB.save(parent);
|
||||
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
|
||||
|
||||
// act
|
||||
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE - setting a new ArrayList rather than using clear()
|
||||
var a_c = new OmBeanListChild("b");
|
||||
secondParent.getChildren().add(a_c);
|
||||
// working here as secondParent itself is not dirty
|
||||
DB.save(secondParent);
|
||||
|
||||
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
|
||||
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
|
||||
// Q: is this expected? A: Rob Bygrave - Yes it is expected
|
||||
assertThat(refreshedParent.getVersion()).isEqualTo(parent.getVersion());
|
||||
assertThat(refreshedParent.getWhenModified()).isEqualTo(parent.getWhenModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usingNewListWithParentDirty_expect_orphanDeleted_fails2() {
|
||||
// setup
|
||||
var parent = new OmBeanListParent();
|
||||
var a_b = new OmBeanListChild("b");
|
||||
parent.getChildren().add(a_b);
|
||||
DB.save(parent);
|
||||
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
|
||||
|
||||
// act
|
||||
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE: using new ArrayList with orphanRemoval
|
||||
var a_c = new OmBeanListChild("c");
|
||||
secondParent.getChildren().add(a_c);
|
||||
// force version increase
|
||||
DB.markAsDirty(secondParent);
|
||||
DB.save(secondParent);
|
||||
|
||||
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
|
||||
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
|
||||
assertThat(refreshedParent.getVersion()).isGreaterThan(parent.getVersion());
|
||||
assertThat(refreshedParent.getWhenModified()).isAfter(parent.getWhenModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usingClearWithParentDirty_expect_orphanDeleted_works() {
|
||||
// setup
|
||||
var parent = new OmBeanListParent();
|
||||
var a_b = new OmBeanListChild("b");
|
||||
parent.getChildren().add(a_b);
|
||||
DB.save(parent);
|
||||
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
|
||||
|
||||
// act
|
||||
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
secondParent.getChildren().clear(); // <!-- HERE: Using clear() with orphanRemoval
|
||||
var a_c = new OmBeanListChild("c");
|
||||
secondParent.getChildren().add(a_c);
|
||||
// force version increase
|
||||
DB.markAsDirty(secondParent);
|
||||
DB.save(secondParent);
|
||||
|
||||
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
|
||||
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
|
||||
assertThat(refreshedParent.getVersion()).isGreaterThan(parent.getVersion());
|
||||
assertThat(refreshedParent.getWhenModified()).isAfter(parent.getWhenModified());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usingNewListWithParentDirty_expect_orphanDeleted_fails() {
|
||||
// setup
|
||||
var parent = new OmBeanListParent();
|
||||
var a_b = new OmBeanListChild("b");
|
||||
parent.getChildren().add(a_b);
|
||||
DB.save(parent);
|
||||
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
|
||||
|
||||
// act
|
||||
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE: new ArrayList with orphanRemoval
|
||||
var a_c = new OmBeanListChild("c");
|
||||
secondParent.getChildren().add(a_c);
|
||||
secondParent.setWhenCreated(Instant.now());
|
||||
DB.save(secondParent);
|
||||
|
||||
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
|
||||
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
|
||||
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
|
||||
assertThat(refreshedParent.getVersion()).isGreaterThan(parent.getVersion());
|
||||
assertThat(refreshedParent.getWhenModified()).isAfter(parent.getWhenModified());
|
||||
}
|
||||
}
|
||||
@@ -6,87 +6,11 @@ import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.EBasic;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class TestFindFutureRowCount extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
void futureCount_doesNotTriggerFlush() throws ExecutionException, InterruptedException {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(100);
|
||||
|
||||
EBasic basic = new EBasic("count_batched");
|
||||
DB.save(basic);
|
||||
|
||||
FutureRowCount<EBasic> futureCount = DB.find(EBasic.class)
|
||||
.where().eq("name", "count_batched")
|
||||
.findFutureCount();
|
||||
|
||||
assertThat(futureCount.get()).isEqualTo(0);
|
||||
|
||||
transaction.flush();
|
||||
|
||||
FutureRowCount<EBasic> futureCountAfter = DB.find(EBasic.class)
|
||||
.where().eq("name", "count_batched")
|
||||
.findFutureCount();
|
||||
|
||||
assertThat(futureCountAfter.get()).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void futureList_doesNotTriggerFlush() throws ExecutionException, InterruptedException {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(100);
|
||||
|
||||
EBasic basic = new EBasic("list_batched");
|
||||
DB.save(basic);
|
||||
|
||||
FutureList<EBasic> futureList = DB.find(EBasic.class)
|
||||
.where().eq("name", "list_batched")
|
||||
.findFutureList();
|
||||
|
||||
assertThat(futureList.get()).isEmpty();
|
||||
|
||||
transaction.flush();
|
||||
|
||||
FutureList<EBasic> futureListAfter = DB.find(EBasic.class)
|
||||
.where().eq("name", "list_batched")
|
||||
.findFutureList();
|
||||
|
||||
assertThat(futureListAfter.get()).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void futureIds_doesNotTriggerFlush() throws ExecutionException, InterruptedException {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
transaction.setBatchSize(100);
|
||||
|
||||
EBasic basic = new EBasic("ids_batched");
|
||||
DB.save(basic);
|
||||
|
||||
FutureIds<EBasic> futureIds = DB.find(EBasic.class)
|
||||
.where().eq("name", "ids_batched")
|
||||
.findFutureIds();
|
||||
|
||||
assertThat(futureIds.get()).isEmpty();
|
||||
|
||||
transaction.flush();
|
||||
|
||||
FutureIds<EBasic> futureIdsAfter = DB.find(EBasic.class)
|
||||
.where().eq("name", "ids_batched")
|
||||
.findFutureIds();
|
||||
|
||||
assertThat(futureIdsAfter.get()).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void count_when_inTransaction() throws Exception {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import jakarta.persistence.PersistenceException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -270,25 +269,23 @@ public class TestQueryFindPagedList extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
void test_forUpdate() {
|
||||
if (!isDb2()) {
|
||||
ResetBasicData.reset();
|
||||
ResetBasicData.reset();
|
||||
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
PagedList<Order> pagedList = DB.find(Order.class).forUpdate().setMaxRows(2).findPagedList();
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
PagedList<Order> pagedList = DB.find(Order.class).forUpdate().setMaxRows(2).findPagedList();
|
||||
|
||||
LoggedSql.start();
|
||||
int totalCount = pagedList.getTotalCount();
|
||||
assertThat(totalCount).isGreaterThan(2);
|
||||
LoggedSql.start();
|
||||
int totalCount = pagedList.getTotalCount();
|
||||
assertThat(totalCount).isGreaterThan(2);
|
||||
|
||||
List<Order> list = pagedList.getList();
|
||||
assertThat(list).hasSize(2);
|
||||
List<Order> list = pagedList.getList();
|
||||
assertThat(list).hasSize(2);
|
||||
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select count(*) from o_order t0;");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(1)).contains(" limit 2 for update;");
|
||||
}
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select count(*) from o_order t0;");
|
||||
if (isH2() || isPostgresCompatible()) {
|
||||
assertThat(sql.get(1)).contains(" limit 2 for update;");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.tests.query;
|
||||
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.bean.FrozenBeans;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.InterceptReadOnly;
|
||||
@@ -7,23 +9,150 @@ import io.ebean.xtest.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.basic.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestQueryOrderById extends BaseTestCase {
|
||||
|
||||
|
||||
private Set<Integer> cachedCustomerIds;
|
||||
|
||||
@Test
|
||||
void cachedBeanContext_attach() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
FrozenBeans cachedBeanContext = testSerialiseCachedBeans(buildCachedBeans());
|
||||
|
||||
testSerialiseCustomer(cachedCustomers.get(0));
|
||||
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
|
||||
txn.attach(cachedBeanContext);
|
||||
|
||||
List<Order> orders = DB.find(Order.class)
|
||||
.findList();
|
||||
|
||||
for (Order order : orders) {
|
||||
Customer customer = order.getCustomer();
|
||||
if (cachedCustomerIds.contains(customer.getId())) {
|
||||
// Illegal to access customer.orders as that was not loaded and no lazy loading is allowed
|
||||
// List<Order> orders1 = customer.getOrders();
|
||||
// assertThat(orders1).isEmpty();
|
||||
// assertThat(orders1).isSameAs(Collections.EMPTY_LIST);
|
||||
|
||||
List<Contact> contacts = customer.getContacts();
|
||||
assertThat(contacts).isNotNull();
|
||||
|
||||
// customer.setContacts(new ArrayList<>());
|
||||
// customer.setName("modified");
|
||||
Address billingAddress = customer.getBillingAddress();
|
||||
if (billingAddress != null) {
|
||||
String line1 = billingAddress.getLine1();
|
||||
Country country = billingAddress.getCountry();
|
||||
}
|
||||
Address shippingAddress = customer.getShippingAddress();
|
||||
// if (shippingAddress != null) {
|
||||
// // shippingAddress.getCountry();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static FrozenBeans testSerialiseCachedBeans(FrozenBeans source) {
|
||||
try {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(os);
|
||||
oos.writeObject(source);
|
||||
oos.close();
|
||||
|
||||
byte[] byteArray = os.toByteArray();
|
||||
|
||||
var is = new ByteArrayInputStream(byteArray);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
FrozenBeans result = (FrozenBeans)ois.readObject();
|
||||
assertThat(result).isNotNull();
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testSerialiseCustomer(Customer source) {
|
||||
try {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(os);
|
||||
oos.writeObject(source);
|
||||
oos.close();
|
||||
|
||||
byte[] byteArray = os.toByteArray();
|
||||
|
||||
var is = new ByteArrayInputStream(byteArray);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Customer customer = (Customer)ois.readObject();
|
||||
|
||||
assertThat(customer.getId()).isEqualTo(source.getId());
|
||||
assertThat(customer.getName()).isEqualTo(source.getName());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Customer> cachedCustomers;
|
||||
|
||||
private FrozenBeans buildCachedBeans() {
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
|
||||
List<Customer> list = DB.find(Customer.class)
|
||||
.setReadOnly(true)
|
||||
//.setDisableLazyLoading(true)
|
||||
.orderBy("id")
|
||||
.setMaxRows(3)
|
||||
.findList();
|
||||
|
||||
// perform some lazy loading if we desire
|
||||
for (Customer customer : list) {
|
||||
customer.getContacts().size();
|
||||
Address billingAddress = customer.getBillingAddress();
|
||||
if (billingAddress != null) {
|
||||
Country country = billingAddress.getCountry();
|
||||
if (country != null) {
|
||||
country.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// can selectively use DisableLazyLoad which is "lazy loading is NO-operation"
|
||||
//for (Customer customer : list) {
|
||||
// DB.beanState(customer).setDisableLazyLoad(true);
|
||||
//}
|
||||
|
||||
cachedCustomerIds = list.stream()
|
||||
.map(BasicDomain::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
cachedCustomers = list;
|
||||
return txn.freezeAndDetach();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void orderById_default_expectNotOrderById() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = DB.find(Customer.class)
|
||||
.select("id,name")
|
||||
.order("id")
|
||||
.orderBy("id")
|
||||
.setFirstRow(1)
|
||||
.setMaxRows(5);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
</parent>
|
||||
|
||||
<name>kotlin querybean generator</name>
|
||||
@@ -21,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -56,14 +56,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-platform-h2</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>13.26.1-jakarta</version>
|
||||
<version>13.26.0-jakarta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user