Compare commits

...
Author SHA1 Message Date
Rob Bygrave 6b2cdc14aa Version 14.0.0 2024-02-15 22:48:38 +13:00
Rob Bygrave 6d712a92a0 Bump ebean-agent to 14.0.0, no functional change 2024-02-15 22:21:09 +13:00
Rob BygraveandGitHub ea11b0c3b6 Merge pull request #3289 from FOCONIS/fix-nested-user-objects
Change semantic of userObjects in nested transaction
2024-02-15 22:10:45 +13:00
Rob BygraveandGitHub 08e8402d05 Merge pull request #3301 from ebean-orm/feature/3295-PC-clear-on-bulk-update
#3295 Clear PersistenceContext on execution of bulk updates or deletes
2024-02-15 22:09:16 +13:00
Rob BygraveandGitHub 006ad79379 Merge branch 'master' into feature/3295-PC-clear-on-bulk-update 2024-02-15 22:09:03 +13:00
Rob BygraveandGitHub 0e063549cd Merge pull request #3327 from ebean-orm/feature/remove-deprecated-commitTransaction
Remove deprecated database.commitTransaction(), migrate to transaction.commit()
2024-02-15 22:07:32 +13:00
Rob BygraveandGitHub 4f0d2cabfb Merge pull request #3325 from ebean-orm/feature/default-batchSize-100
Change default persistBatchSize from 20 to 100 (as a better default value)
2024-02-15 22:07:14 +13:00
Rob Bygrave 80b2d9f983 Remove deprecated database.commitTransaction(), migrate to transaction.commit()
Remove the deprecated methods:
- DB.commitTransaction()
- DB.rollbackTransaction()
- DB.endTransaction()
- database.commitTransaction()
- database.rollbackTransaction()
- database.endTransaction()

Migrate to using try-with-resources and transaction.commit(), transaction.rollback()
2024-02-15 21:56:57 +13:00
Rob Bygrave 287d0c467d #3326 Update the test example of Postgres DML with RETURNING clause to use explicit transactions and transaction.addModification() 2024-02-11 14:25:01 +13:00
Rob Bygrave a8835379e7 #3326 Add test as example of Postgres DML with RETURNING clause 2024-02-11 13:18:19 +13:00
Rob Bygrave e4df20b9dc Update test TestPersistCascade with default batch size 100 2024-02-10 13:28:04 +13:00
Rob Bygrave 261b13ef4b Version 13.26.1 2024-02-10 12:40:30 +13:00
Rob Bygrave 7639034d7c Bump ebean-agent to 13.26.1 (no functional change here) 2024-02-10 12:17:47 +13:00
Rob Bygrave e6e53e0d93 Change default persistBatchSize from 20 to 100 (as a better default value)
This is the batch size used with PreparedStatement executeBatch() with
batched inserts, updates and deletes. 20 is really on the low side and
bumping this default to 100 seems good and right.
2024-02-10 12:15:50 +13:00
Rob BygraveandGitHub c71971eb5c Merge pull request #3322 from ebean-orm/fix/3319
(fix) Future queries do not trigger flush on BatchedPstmtHolder for #3319
2024-02-10 12:12:47 +13:00
Rob BygraveandGitHub 357af58db4 Merge pull request #3324 from ebean-orm/feature/postgres_insertOnConflict
Add support for Postgres INSERT ON CONFLICT update | nothing
2024-02-10 12:08:44 +13:00
Rob BygraveandGitHub 0abdb1550a Merge pull request #3310 from Ichtil/one_to_many_list_clear_test
Previous entities are not deleted when replacing OneToMany collection with a new one
2024-02-10 12:03:16 +13:00
Rob Bygrave c32fc814f6 Add support for insert/insertAll with both options and explicit transaction 2024-02-10 12:00:32 +13:00
Rob Bygrave 8e035939dc Add support for Postgres INSERT ON CONFLICT update | nothing
Adds InsertOptions with ability to control the options used
for insert with Postgres around ON CONFLICT.
2024-02-10 01:07:44 +13:00
Rob Bygrave edf98ee250 Fix test OneToManyListMarkAsDirtyTest with some wait time 2024-02-09 15:46:34 +13:00
Rob Bygrave 5f0a75a130 No effective change, update test renaming internal variables 2024-02-09 15:26:28 +13:00
Rob Bygrave d2f16cbf6a #3310 Fix for orphanRemoval with updated parent and 'vanilla collection'
The issue fixed here is a timing one where the parent bean is being updated.
The updated parent bean has its internal state reset before the cascade down
to the SaveManyBeans where for this case it needs to identify is the 'vanilla'
collection has set (via setChildren(new ArrayList()).

This fix is a change that for updated beans the dirtyProperties is always obtained
and then use this for the isChangedProperty() check.
2024-02-09 15:24:47 +13:00
Rob Bygrave 04ba81d12f #3310 Update test only, reuse existing entity beans
- Reuse the existing OmBeanListParent and child
- Simplify the test setup code
- Rename test methods to maybe better reflect what I think is failing

Noting that markAsDirty doesn't specifically have anything to do with this bug but it's more on whether the parent bean is dirty or dirty (markAsDirty is just a way to make the parent bean dirty).
2024-02-09 08:30:42 +13:00
Rob Bygrave f63e7ed5af Add test only for orphan removal to TestOrphanRemovalOverwrite
Using clear() and add() when the same id value is used
2024-02-08 00:14:22 +13:00
Rob Bygrave 66940c0f14 Update tests only for BeanList BeanSet BeanMap
Use Product entity with equals/hashCode implementation added via ebean enhancement
2024-02-07 22:29:05 +13:00
Rob Bygrave 1f48b3a6b3 (fix) Future queries do not trigger flush on BatchedPstmtHolder for #3319
This change is that findFutureCount, findFutureList, findFutureIds do not trigger a flush on BatchedPstmtHolder.

This is to address the possible ConcurrentModificationException that could occur at BatchedPstmtHolder.closeStatements(BatchedPstmtHolder.java:153)
2024-02-03 08:20:58 +13:00
Rob BygraveandGitHub 7d368097e9 Merge pull request #3321 from ebean-orm/feature/tidy-OrmQueryRequest-readOnly
Tidy OrmQueryRequest isReadOnly, just use query.isReadOnly instead
2024-02-02 14:44:06 +13:00
Rob Bygrave c849e29316 Tidy OrmQueryRequest isReadOnly, just use query.isReadOnly instead 2024-02-02 14:43:31 +13:00
Rob BygraveandGitHub c78a3dd6c4 Merge pull request #3318 from FOCONIS/fix-db2-test
Exclude test for DB2
2024-01-31 22:57:49 +13:00
Noemi Praml a4455ddbf2 Exclude test for DB2 2024-01-31 10:17:16 +01:00
Rob BygraveandGitHub 9787af77e4 Merge pull request #3315 from FOCONIS/db2-select-for-update
ADD: DB2 supports select .. for update queries
2024-01-30 22:53:19 +13:00
Noemi Praml 3786fb09a5 ADD: DB2 supports select .. for update queries 2024-01-29 15:12:21 +01:00
Rob Bygrave 6645e5b9ec Update the test comments in TestPersistenceContextQueryScope
To reflect the behaviour with #3295
2024-01-19 08:58:19 +13:00
Jan Klička 006e33cb3e One to many replacing collection failing test cases 2024-01-18 17:29:24 +01:00
Jan Klička e80e8e027a One to many replacing collection failing test cases 2024-01-18 16:49:04 +01:00
Rob Bygrave 3576aafffc #3295 When isAutoPersistUpdates is used do NOT clear the PersistenceContext
Also make improvements to the test asserts in TestPersistenceContextQueryScope
2024-01-10 23:23:47 +13:00
Rob Bygrave 66234249c6 #3295 Clear PersistenceContext on execution of bulk updates or deletes
Using SqlUpdate or an ORM Update query clear the appropriate part of
the PersistenceContext. The effect is that ORM queries executed after
a bulk update will effectively load a fresh copy of the data from the
database and will not reuse an instance from the persistence context
if the bean in question had already been loaded.
2024-01-09 07:44:27 +13:00
Roland Praml 6f64821584 Change semantic of userObjects in nested transaction 2023-12-08 14:50:30 +01:00
125 changed files with 1948 additions and 671 deletions
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -41,7 +41,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<artifactId>composites</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean api</name>
-49
View File
@@ -266,55 +266,6 @@ public final class DB {
getDefault().register(transactionCallback);
}
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
public static void commitTransaction() {
getDefault().commitTransaction();
}
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
public static void rollbackTransaction() {
getDefault().rollbackTransaction();
}
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* It is preferable to use <em>try with resources</em> rather than this.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
*
* <pre>{@code
* DB.beginTransaction();
* try {
* // do some fetching and or persisting
*
* // commit at the end
* DB.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* DB.endTransaction();
* }
* }</pre>
*/
public static void endTransaction() {
getDefault().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
@@ -0,0 +1,104 @@
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;
}
}
}
+31 -43
View File
@@ -666,49 +666,6 @@ public interface Database {
*/
void flush();
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
void commitTransaction();
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
void rollbackTransaction();
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
* <p>
* <pre>{@code
*
* database.beginTransaction();
* try {
* // do some fetching and or persisting ...
*
* // commit at the end
* database.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* database.endTransaction();
* }
*
* }</pre>
*/
void endTransaction();
/**
* Refresh the values of a bean.
* <p>
@@ -1227,22 +1184,53 @@ 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.
*/
@@ -0,0 +1,119 @@
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();
}
}
@@ -236,7 +236,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 20;
private int persistBatchSize = 100;
private EnumType defaultEnumType = EnumType.ORDINAL;
+26 -26
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -125,13 +125,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -155,37 +155,37 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
+6 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
@@ -3,6 +3,8 @@ package io.ebeaninternal.api;
import io.ebean.TxScope;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Used internally to handle the scoping of transactions for methods.
@@ -47,6 +49,11 @@ public final class ScopeTrans {
private boolean nestedCommit;
private boolean nestedUseSavepoint;
/**
* The UserObjects when using in nested transactions.
*/
private Map<String, Object> userObjects;
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope) {
this.rollbackOnChecked = rollbackOnChecked;
this.created = created;
@@ -218,4 +225,17 @@ public final class ScopeTrans {
return e instanceof RuntimeException || rollbackOnChecked;
}
public void putUserObject(String name, Object value) {
if (userObjects == null) {
userObjects = new HashMap<>();
}
userObjects.put(name, value);
}
public Object getUserObject(String name) {
if (userObjects == null) {
return null;
}
return userObjects.get(name);
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import io.ebeaninternal.server.util.ArrayStack;
import jakarta.persistence.PersistenceException;
/**
@@ -173,4 +172,31 @@ public final class ScopedTransaction extends SpiTransactionProxy {
return current.caughtThrowable(e);
}
/**
* New user objects are always written to the current ScopeTrans.
*/
@Override
public void putUserObject(String name, Object value) {
current.putUserObject(name, value);
}
/**
* Returns the userObject in the stack, Herew we search
* the stack and return the first found userObject
*/
@Override
public Object getUserObject(String name) {
Object obj = current.getUserObject(name);
if (obj != null) {
return obj;
}
for (ScopeTrans trans : stack) {
obj = trans.getUserObject(name);
if (obj != null) {
return obj;
}
}
return transaction.getUserObject(name);
}
}
@@ -86,6 +86,11 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
*/
SpiTransactionManager transactionManager();
/**
* End the current transaction if it is active.
*/
void endTransaction();
/**
* Return all the descriptors.
*/
@@ -654,6 +654,16 @@ 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>
@@ -756,16 +756,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
currentTransaction().flush();
}
@Override
public void commitTransaction() {
currentTransaction().commit();
}
@Override
public void rollbackTransaction() {
currentTransaction().rollback();
}
@Override
public void endTransaction() {
Transaction transaction = transactionManager.inScope();
@@ -1273,6 +1263,7 @@ 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) {
@@ -1291,6 +1282,7 @@ 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) {
@@ -1309,6 +1301,7 @@ 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()) {
@@ -1651,41 +1644,50 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}, transaction);
}
/**
* Insert the bean.
*/
@Override
public void insert(Object bean) {
insert(bean, null);
persister.insert(checkEntityBean(bean), null, null);
}
@Override
public void insert(Object bean, @Nullable InsertOptions insertOptions) {
persister.insert(checkEntityBean(bean), insertOptions, null);
}
/**
* Insert the bean with a transaction.
*/
@Override
public void insert(Object bean, @Nullable Transaction transaction) {
persister.insert(checkEntityBean(bean), transaction);
persister.insert(checkEntityBean(bean), null, transaction);
}
@Override
public void insert(Object bean, InsertOptions insertOptions, Transaction transaction) {
persister.insert(checkEntityBean(bean), insertOptions, transaction);
}
/**
* Insert all beans in the collection.
*/
@Override
public void insertAll(Collection<?> beans) {
insertAll(beans, null);
insertAll(beans, null, null);
}
@Override
public void insertAll(Collection<?> beans, InsertOptions options) {
insertAll(beans, options, 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), txn);
persister.insert(checkEntityBean(bean), options, txn);
}
return 0;
}, transaction);
@@ -35,7 +35,6 @@ 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;
@@ -52,7 +51,6 @@ 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();
}
@@ -135,13 +133,6 @@ 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.
*/
@@ -782,4 +773,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
public int forwardOnlyFetchSize() {
return queryEngine.forwardOnlyFetchSize();
}
public void clearContext() {
if (!transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
}
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.InsertOptions;
import io.ebean.ValuePair;
import io.ebean.annotation.DocStoreMode;
import io.ebean.bean.EntityBean;
@@ -124,6 +125,7 @@ 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) {
@@ -380,6 +382,14 @@ 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.
*/
@@ -865,8 +875,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
setNotifyCache();
boolean isChangeLog = beanDescriptor.isChangeLog();
if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
// get the dirty properties for update notification to the doc store
if (type == Type.UPDATE) {
// get the dirty properties for notify cache & orphanRemoval of vanilla collection detection
dirtyProperties = intercept.dirtyProperties();
}
if (isChangeLog) {
@@ -1408,4 +1418,12 @@ 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;
}
}
@@ -77,10 +77,13 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
*/
@Override
public void postExecute() {
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
if (OrmUpdateType.INSERT != ormUpdateType && !transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
if (startNanos > 0) {
persistExecute.collectOrmUpdate(label, startNanos);
}
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
String tableName = ormUpdate.baseTable();
if (transaction.isLogSummary()) {
transaction.logSummary("{0} table[{1}] rows[{2}] bind[{3}]", ormUpdateType, tableName, rowCount, bindLog);
@@ -3,10 +3,13 @@ package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.PersistExecute;
import io.ebeaninternal.server.persist.TrimLogSql;
import java.util.List;
/**
* Persist request specifically for CallableSql.
*/
@@ -156,6 +159,14 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
@Override
public void postExecute() {
if (sqlType != SqlType.SQL_INSERT && !transaction.isAutoPersistUpdates()) {
List<BeanDescriptor<?>> descriptors = server.descriptors(tableName);
if (descriptors != null) {
for (BeanDescriptor<?> descriptor : descriptors) {
descriptor.contextClear(transaction.persistenceContext());
}
}
}
if (startNanos > 0) {
persistExecute.collectSqlUpdate(label, startNanos);
}
@@ -1,11 +1,7 @@
package io.ebeaninternal.server.core;
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.avaje.lang.Nullable;
import io.ebean.*;
import io.ebean.bean.EntityBean;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiSqlUpdate;
@@ -31,9 +27,9 @@ public interface Persister {
void update(EntityBean entityBean, Transaction t);
/**
* Force an Insert using the given bean.
* Perform an Insert using the given bean.
*/
void insert(EntityBean entityBean, Transaction t);
void insert(EntityBean entityBean, @Nullable InsertOptions insertOptions, @Nullable Transaction t);
/**
* Insert or update the bean depending on its state.
@@ -44,7 +40,6 @@ 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);
@@ -2056,6 +2056,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
pc.clear(rootBeanType, idValue);
}
/**
* Clear a bean from the persistence context.
*/
public void contextClear(PersistenceContext pc) {
pc.clear(rootBeanType);
}
/**
* Delete a bean from the persistence context (such that we don't fetch it in the same transaction).
*/
@@ -399,7 +399,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
* Return the BeanDescriptors mapped to the table.
*/
public List<BeanDescriptor<?>> descriptors(String tableName) {
return tableToDescMap.get(tableName.toLowerCase());
return tableName == null ? Collections.emptyList() : tableToDescMap.get(tableName.toLowerCase());
}
/**
@@ -411,7 +411,7 @@ public final class DefaultPersister implements Persister {
if (bean._ebean_getIntercept().isUpdate()) {
update(bean, t);
} else {
insert(bean, t);
insert(bean, null, t);
}
}
@@ -419,12 +419,15 @@ public final class DefaultPersister implements Persister {
* Insert this bean.
*/
@Override
public void insert(EntityBean bean, Transaction t) {
public void insert(EntityBean bean, InsertOptions insertOptions, 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 parentBean._ebean_getIntercept().isChangedProperty(many.propertyIndex());
return request.isChangedProperty(many.propertyIndex());
}
private void removeAssocManyOrphans() {
@@ -1,11 +1,15 @@
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;
@@ -26,7 +30,7 @@ public final class GenerateDmlRequest {
++bindColumnCount;
sb.append(prefix);
sb.append(column);
//sb.append(expr);
columns.add(column);
if (insertMode > 0) {
if (insertMode++ > 1) {
insertBindBuffer.append(',');
@@ -75,4 +79,8 @@ 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.getSql(withId, persistRequest.isPublish());
sql = meta.sql(withId, persistRequest.isPublish(), persistRequest.insertOptions());
PreparedStatement pstmt;
if (persistRequest.isBatched()) {
pstmt = pstmtBatch(t, sql, persistRequest, useGeneratedKeys);
@@ -134,7 +134,8 @@ public final class InsertHandler extends DmlHandler {
if (idValue != null) {
persistRequest.setGeneratedKey(idValue);
}
} else {
} else if (persistRequest.insertOptions() == null) {
// insert on conflict do nothing can not return generated key
throw new PersistenceException("Autoincrement getGeneratedKeys() returned no rows?");
}
}
@@ -1,5 +1,6 @@
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;
@@ -36,9 +37,11 @@ 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;
@@ -47,8 +50,8 @@ final class InsertMeta {
String tableName = desc.baseTable();
String draftTableName = desc.draftTable();
this.sqlWithId = genSql(false, tableName, false);
this.sqlDraftWithId = desc.isDraftable() ? genSql(false, draftTableName, true) : sqlWithId;
this.sqlWithId = sql(false, tableName, false);
this.sqlDraftWithId = desc.isDraftable() ? sql(false, draftTableName, true) : sqlWithId;
// only available for single Id property
if (id.isConcatenated()) {
@@ -72,8 +75,8 @@ final class InsertMeta {
this.supportsGetGeneratedKeys = dbPlatform.dbIdentity().isSupportsGetGeneratedKeys();
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
}
this.sqlNullId = genSql(true, tableName, false);
this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId;
this.sqlNullId = sql(true, tableName, false);
this.sqlDraftNullId = desc.isDraftable() ? sql(true, draftTableName, true) : sqlNullId;
}
}
@@ -137,9 +140,20 @@ final class InsertMeta {
}
/**
* get the sql based whether the id value(s) are null.
* Return the sql for the given options.
*/
public String getSql(boolean withId, boolean publish) {
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) {
if (withId) {
return publish ? sqlWithId : sqlDraftWithId;
} else {
@@ -147,12 +161,18 @@ final class InsertMeta {
}
}
private String genSql(boolean nullId, String table, boolean draftTable) {
private String sql(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)) {
return request.append(defaultValues()).toString();
request.append(defaultValues());
return;
}
request.append(" (");
if (!nullId) {
@@ -172,7 +192,6 @@ final class InsertMeta {
request.append(") values (");
request.append(request.insertBindBuffer());
request.append(")");
return request.toString();
}
private String defaultValues() {
@@ -196,5 +215,4 @@ final class InsertMeta {
&& discriminator == null
&& (draftTable ? all.isEmpty() : allExcludeDraftOnly.isEmpty());
}
}
@@ -0,0 +1,14 @@
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);
}
@@ -0,0 +1,113 @@
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));
}
}
}
@@ -0,0 +1,29 @@
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 = request.isReadOnly();
this.readOnly = query.isReadOnly();
this.disableLazyLoading = query.isDisableLazyLoading();
this.objectGraphNode = query.parentNode();
this.profilingListener = query.profilingListener();
@@ -74,6 +74,9 @@ public final class CQueryEngine {
if (request.logSql()) {
request.logSql("{0}; --bind({1}) --micros({2}) --rows({3})", query.generatedSql(), query.bindLog(), query.micros(), rows);
}
if (rows > 0) {
request.clearContext();
}
return rows;
} catch (SQLException e) {
throw translate(request, query.bindLog(), query.generatedSql(), e);
@@ -61,6 +61,7 @@ final class CQueryUpdate implements SpiProfileTransactionEvent, CancelableQuery
/**
* Execute the update or delete statement returning the row count.
*/
@SuppressWarnings("resource")
public int execute() throws SQLException {
long startNano = System.nanoTime();
try {
@@ -109,6 +110,7 @@ final class CQueryUpdate implements SpiProfileTransactionEvent, CancelableQuery
pstmt = null;
}
@SuppressWarnings("resource")
@Override
public void profile() {
transaction()
@@ -51,6 +51,10 @@ 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
@@ -58,6 +58,7 @@ 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.
@@ -971,6 +972,16 @@ 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;
@@ -2,12 +2,13 @@ package io.ebeaninternal.server.util;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Iterator;
import java.util.List;
/**
* Stack based on ArrayList.
*/
public class ArrayStack<E> {
public class ArrayStack<E> implements Iterable<E> {
private final List<E> list;
@@ -89,4 +90,9 @@ public class ArrayStack<E> {
public boolean contains(E o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean postgis types</name>
@@ -19,14 +19,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
@@ -62,7 +62,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
@@ -63,14 +63,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
@@ -84,7 +84,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,28 +22,28 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
@@ -57,7 +57,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<artifactId>ebean-spring-txn</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</parent>
<name>ebean test</name>
@@ -33,20 +33,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -149,14 +149,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.0-jakarta</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
@@ -1,5 +1,6 @@
package io.ebean.xtest.base;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.AfterEach;
@@ -18,15 +19,17 @@ import org.tests.model.basic.ResetBasicData;
*/
public abstract class TransactionalTestCase extends BaseTestCase {
private Transaction transaction;
@BeforeEach
public void startTransaction() {
ResetBasicData.reset();
DB.beginTransaction();
transaction = DB.beginTransaction();
}
@AfterEach
public void endTransaction() {
DB.rollbackTransaction();
DB.endTransaction();
transaction.rollback();
transaction.end();
}
}
@@ -3,6 +3,7 @@ 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;
@@ -13,22 +14,22 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BeanListTest {
private final Object object1 = new Object();
private final Object object2 = new Object();
private final Object object3 = new Object();
private final Product object1 = new Product(1);
private final Product object2 = new Product(2);
private final Product object3 = new Product(3);
private List<Object> all() {
List<Object> all = new ArrayList<>();
all.add(object1);
all.add(object2);
all.add(object3);
all.add(new Product(1));
all.add(new Product(2));
all.add(new Product(3));
return all;
}
private List<Object> some() {
List<Object> some = new ArrayList<>();
some.add(object2);
some.add(object3);
some.add(new Product(2));
some.add(new Product(3));
return some;
}
@@ -163,14 +164,15 @@ 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(object2);
list.remove(object3);
list.remove(all.get(1));
list.remove(all.get(2));
assertThat(list.modifyAdditions()).containsOnly(object1);
assertThat(list.modifyRemovals()).isEmpty();
@@ -179,13 +181,14 @@ 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(some());
list.removeAll(List.of(all.get(1), all.get(2)));
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.EBasic;
import org.tests.model.basic.Product;
import java.util.*;
@@ -14,24 +14,24 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
public class BeanMapTest {
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 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 Map<String, Object> all() {
Map<String, Object> all = new LinkedHashMap<>();
all.put("1", object1);
all.put("2", object2);
all.put("3", object3);
all.put("1", new Product(1));
all.put("2", new Product(2));
all.put("3", new Product(3));
return all;
}
private Map<String, Object> some() {
Map<String, Object> all = new LinkedHashMap<>();
all.put("2", object2);
all.put("3", object3);
all.put("2", new Product(2));
all.put("3", new Product(3));
return all;
}
@@ -73,8 +73,8 @@ public class BeanMapTest {
@Test
public void testAdd_given_someAlreadyIn() {
BeanMap<String, Object> map = new BeanMap<>(some());
Map<String, Object> some = new LinkedHashMap<>(Map.of("2", object2, "3", object3));
BeanMap<String, Object> map = new BeanMap<>(some);
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
// act
@@ -90,11 +90,13 @@ public class BeanMapTest {
@Test
public void testAddSome_given_someAlreadyIn() {
BeanMap<String, Object> map = new BeanMap<>(some());
Map<String, Object> some = new LinkedHashMap<>(Map.of("2", object2, "3", object3));
BeanMap<String, Object> map = new BeanMap<>(some);
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
// act
map.putAll(all());
Map<String, Object> all = Map.of("1", object1, "2", object2, "3", object3);
map.putAll(all);
assertThat(map.modifyAdditions()).containsOnly(object1);
assertThat(map.modifyRemovals()).isEmpty();
@@ -179,7 +181,7 @@ public class BeanMapTest {
@Test
public void testClear_given_someBeansInAdditions() {
BeanMap<String, EBasic> map = newModifyListeningMap();
BeanMap<String, Product> map = newModifyListeningMap();
map.put("2", object2);
map.put("3", object3);
@@ -193,7 +195,7 @@ public class BeanMapTest {
@Test
public void keySet_add_whenModifyListening() {
BeanMap<String, EBasic> map = newModifyListeningMap();
BeanMap<String, Product> map = newModifyListeningMap();
assertThrows(UnsupportedOperationException.class, () -> map.keySet().add("3"));
}
@@ -205,7 +207,7 @@ public class BeanMapTest {
@Test
public void keySet_addAll_whenModifyListening() {
BeanMap<String, EBasic> map = newModifyListeningMap();
BeanMap<String, Product> map = newModifyListeningMap();
assertThrows(UnsupportedOperationException.class, () -> map.keySet().addAll(asList("3", "4")));
}
@@ -317,13 +319,13 @@ public class BeanMapTest {
@Test
public void values_add() {
BeanMap<String, EBasic> map = new BeanMap<>();
BeanMap<String, Product> map = new BeanMap<>();
assertThrows(UnsupportedOperationException.class, () -> map.values().add(object3));
}
@Test
public void values_addAll() {
BeanMap<String, EBasic> map = new BeanMap<>();
BeanMap<String, Product> map = new BeanMap<>();
assertThrows(UnsupportedOperationException.class, () -> map.values().addAll(asList(object3, object5)));
}
@@ -337,8 +339,8 @@ public class BeanMapTest {
@Test
public void entrySet_clear() {
final BeanMap<String, EBasic> map = newModifyListeningMap();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final BeanMap<String, Product> map = newModifyListeningMap();
final Set<Map.Entry<String, Product>> entries = map.entrySet();
entries.clear();
assertThat(entries).isEmpty();
@@ -348,8 +350,8 @@ public class BeanMapTest {
@Test
public void entrySet_remove() {
final BeanMap<String, EBasic> map = newModifyListeningMap5();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final BeanMap<String, Product> map = newModifyListeningMap5();
final Set<Map.Entry<String, Product>> entries = map.entrySet();
assertThat(map).hasSize(5);
@@ -365,8 +367,8 @@ public class BeanMapTest {
@Test
public void entrySet_remove_whenNotEqualValue() {
final BeanMap<String, EBasic> map = newModifyListeningMap5();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final BeanMap<String, Product> map = newModifyListeningMap5();
final Set<Map.Entry<String, Product>> entries = map.entrySet();
assertThat(map).hasSize(5);
@@ -379,11 +381,11 @@ public class BeanMapTest {
@Test
public void entrySet_iterator_remove() {
final BeanMap<String, EBasic> map = newModifyListeningMap5();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final Iterator<Map.Entry<String, EBasic>> iterator = entries.iterator();
final BeanMap<String, Product> map = newModifyListeningMap5();
final Set<Map.Entry<String, Product>> entries = map.entrySet();
final Iterator<Map.Entry<String, Product>> iterator = entries.iterator();
while (iterator.hasNext()) {
final Map.Entry<String, EBasic> entry = iterator.next();
final Map.Entry<String, Product> entry = iterator.next();
if (entry.getKey().equals("2") || entry.getKey().equals("5")) {
iterator.remove();
}
@@ -395,8 +397,8 @@ public class BeanMapTest {
@Test
public void entrySet_removeAll() {
final BeanMap<String, EBasic> map = newModifyListeningMap5();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final BeanMap<String, Product> map = newModifyListeningMap5();
final Set<Map.Entry<String, Product>> 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);
@@ -406,8 +408,8 @@ public class BeanMapTest {
@Test
public void entrySet_retainAll() {
final BeanMap<String, EBasic> map = newModifyListeningMap5();
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
final BeanMap<String, Product> map = newModifyListeningMap5();
final Set<Map.Entry<String, Product>> 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);
@@ -415,15 +417,15 @@ public class BeanMapTest {
assertThat(map.modifyRemovals()).containsOnly(object2, object3, object5);
}
private BeanMap<String, EBasic> newModifyListeningMap() {
BeanMap<String, EBasic> map = new BeanMap<>();
private BeanMap<String, Product> newModifyListeningMap() {
BeanMap<String, Product> map = new BeanMap<>();
map.put("1", object1);
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
return map;
}
private BeanMap<String, EBasic> newModifyListeningMap5() {
BeanMap<String, EBasic> map = new BeanMap<>();
private BeanMap<String, Product> newModifyListeningMap5() {
BeanMap<String, Product> map = new BeanMap<>();
map.put("1", object1);
map.put("2", object2);
map.put("3", object3);
@@ -3,6 +3,7 @@ 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;
@@ -12,22 +13,22 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BeanSetTest {
Object object1 = new Object();
Object object2 = new Object();
Object object3 = new Object();
Product object1 = new Product(1);
Product object2 = new Product(2);
Product object3 = new Product(3);
private Set<Object> all() {
Set<Object> all = new LinkedHashSet<>();
all.add(object1);
all.add(object2);
all.add(object3);
all.add(new Product(1));
all.add(new Product(2));
all.add(new Product(3));
return all;
}
private Set<Object> some() {
Set<Object> some = new LinkedHashSet<>();
some.add(object2);
some.add(object3);
some.add(new Product(2));
some.add(new Product(3));
return some;
}
@@ -99,7 +100,9 @@ public class BeanSetTest {
BeanSet<Object> set = new BeanSet<>();
set.setModifyListening(BeanCollection.ModifyListenMode.ALL);
set.addAll(all());
Set<Object> all = Set.of(object1, object2, object3);
set.addAll(all);
assertThat(set.modifyAdditions()).containsOnly(object1, object2, object3);
// act
@@ -115,11 +118,13 @@ public class BeanSetTest {
BeanSet<Object> set = new BeanSet<>();
set.setModifyListening(BeanCollection.ModifyListenMode.ALL);
set.addAll(all());
Set<Object> all = Set.of(object1, object2, object3);
set.addAll(all);
assertThat(set.modifyAdditions()).containsOnly(object1, object2, object3);
// act
set.removeAll(some());
set.removeAll(Set.of(object2, object3));
assertThat(set.modifyAdditions()).containsOnly(object1);
assertThat(set.modifyRemovals()).isEmpty();
@@ -578,14 +578,6 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
public void flush() {
}
@Override
public void commitTransaction() {
}
@Override
public void rollbackTransaction() {
}
@Override
public void endTransaction() {
}
@@ -222,21 +222,6 @@ public class TDSpiServer implements SpiServer {
}
@Override
public void commitTransaction() {
}
@Override
public void rollbackTransaction() {
}
@Override
public void endTransaction() {
}
@Override
public void refresh(Object bean) {
@@ -453,21 +438,41 @@ 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;
@@ -79,9 +79,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
@ForPlatform({Platform.H2})
@Test
public void end_withoutActiveTransaction_isFine() {
assertNull(DB.currentTransaction());
DB.endTransaction();
}
@ForPlatform({Platform.H2})
@@ -1,5 +1,6 @@
package org.tests.basic;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.BeanState;
import io.ebean.DB;
@@ -36,13 +37,11 @@ public class TestDynamicUpdate extends BaseTestCase {
server.save(b2);
server.beginTransaction();
try {
try (Transaction txn = server.beginTransaction()) {
EMain b3 = server.find(EMain.class, b.getId());
assertEquals("ABC", b3.getEmbeddable().getDescription());
} finally {
server.endTransaction();
}
EMain b4 = server.find(EMain.class, b.getId());
b4.setName("bbb");
b4.getEmbeddable().setDescription("123");
@@ -1,5 +1,6 @@
package org.tests.basic;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -17,8 +18,7 @@ public class TestInheritRef extends BaseTestCase {
@Test
public void testAssocOne() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.createUpdate(Vehicle.class, "delete from vehicle");
Car c = new Car();
@@ -52,9 +52,6 @@ public class TestInheritRef extends BaseTestCase {
assertEquals(1, found);
assertTrue(foundTruck.getCapacity() == 20D);
} finally {
DB.rollbackTransaction();
}
}
}
@@ -47,10 +47,9 @@ public class TestPersistenceContext extends BaseTestCase {
// implicit transaction with its own persistence context
Order oBefore = DB.find(Order.class, 1);
// start a persistence context
DB.beginTransaction();
Order order;
try {
try (Transaction txn = DB.beginTransaction()) {
order = DB.find(Order.class, 1);
// not the same instance ...as a different persistence context
assertNotSame(order, oBefore);
@@ -63,9 +62,6 @@ public class TestPersistenceContext extends BaseTestCase {
// all the same instance
assertSame(order, o2);
assertSame(order, o3);
} finally {
DB.endTransaction();
}
// implicit transaction with its own persistence context
@@ -74,8 +70,7 @@ public class TestPersistenceContext extends BaseTestCase {
assertNotSame(oAfter, order);
// start a persistence context
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Order testOrder = ResetBasicData.createOrderCustAndOrder("testPC");
Integer id = testOrder.getCustomer().getId();
Integer orderId = testOrder.getId();
@@ -94,9 +89,6 @@ public class TestPersistenceContext extends BaseTestCase {
assertEquals(customer.getId(), customer2.getId());
assertSame(customer, customer2);
} finally {
DB.endTransaction();
}
}
@@ -27,14 +27,14 @@ public class TestQueryForUpdate extends BaseTestCase {
try (final Transaction transaction = DB.beginTransaction()) {
query = DB.find(Customer.class)
.forUpdate()
.order().desc("id");
.orderBy().desc("id");
query.findList();
}
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("with (updlock)");
} else if (!isDb2()){
} else {
assertThat(sqlOf(query)).contains("for update");
}
}
@@ -48,21 +48,21 @@ public class TestQueryForUpdate extends BaseTestCase {
query = DB.find(Customer.class)
.forUpdate()
.setMaxRows(3)
.order().desc("id");
.orderBy().desc("id");
query.findList();
}
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("with (updlock)");
} else if (!isOracle() && !isDb2()) {
} else if (!isOracle()) {
// 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})
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
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})
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
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})
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2})
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()
.order().desc("id");
.orderBy().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)
.order().desc("id");
.orderBy().desc("id");
List<Customer> list = query.findList();
Customer first = list.get(0);
@@ -1,5 +1,6 @@
package org.tests.cache;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -26,8 +27,7 @@ public class TestCacheInterceptSaveWhenLazyLoaded extends BaseTestCase {
order.setCustomer(customer);
DB.save(order);
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Order foundOrder = DB.find(Order.class)
.where().eq("id", order.getId())
@@ -47,9 +47,6 @@ public class TestCacheInterceptSaveWhenLazyLoaded extends BaseTestCase {
assertSame(foundOrder, order1);
assertTrue(DB.beanState(foundOrder).isDirty());
} finally {
DB.endTransaction();
}
// cleanup
@@ -1,6 +1,7 @@
package org.tests.genkey;
import io.ebean.DB;
import io.ebean.Transaction;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.TOne;
@@ -19,12 +20,10 @@ public class TestGeneratedKeys {
c1.setName("Two");
c1.setDescription("Test Gen Key Two");
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.save(c);
DB.save(c1);
} finally {
DB.commitTransaction();
txn.commit();
}
Integer id = c.getId();
assertNotNull(id);
@@ -0,0 +1,411 @@
package org.tests.insert;
import io.ebean.*;
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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
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());
}
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
@Test
void updateQueryReturning() throws SQLException {
Database db = DB.getDefault();
db.truncate(EPersonOnline.class);
var bean1 = newBean("a1@bee.com");
var bean2 = newBean("a2@cee.com");
var bean3 = newBean("a3@bee.com");
db.saveAll(bean1, bean2, bean3);
String sql = "update e_person_online set email = concat('x',email) where email like ? returning id, email, online_status";
try (Transaction txn = db.createTransaction()) {
Connection connection = txn.connection();
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
pstmt.setString(1, "%bee.com");
try (ResultSet resultSet = pstmt.executeQuery()) {
while (resultSet.next()) {
long id = resultSet.getLong(1);
String email = resultSet.getString(2);
boolean status = resultSet.getBoolean(3);
// do something with the id, email and status
assertThat(id).isGreaterThan(0);
assertThat(email).startsWith("x");
assertThat(status).isTrue();
}
}
}
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<SqlRow> sqlRowList = DB.sqlQuery(sql)
.setParameter("%bee.com")
.findList();
assertThat(sqlRowList).hasSize(2);
assertThat(sqlRowList.get(0).getString("email")).startsWith("xx");
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<ReturnDto> dtoList = db.findDto(ReturnDto.class, sql)
.setParameter("%bee.com")
.findList();
assertThat(dtoList).hasSize(2);
assertThat(dtoList.get(0).email).startsWith("xxx");
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<ReturnDto2> dtoList2 = db.findDto(ReturnDto2.class, sql)
.setParameter("%bee.com")
.findList();
assertThat(dtoList2).hasSize(2);
assertThat(dtoList2.get(0).email).startsWith("xxxx");
assertThat(dtoList2.get(0).id).isGreaterThan(0);
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
}
public static class ReturnDto {
private final long id;
private final String email;
private final boolean onlineStatus;
public ReturnDto(long id, String email, boolean onlineStatus) {
this.id = id;
this.email = email;
this.onlineStatus = onlineStatus;
}
}
public static class ReturnDto2 {
private long id;
private String email;
private boolean onlineStatus;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isOnlineStatus() {
return onlineStatus;
}
public void setOnlineStatus(boolean onlineStatus) {
this.onlineStatus = onlineStatus;
}
}
private static EPersonOnline newBean(String email) {
EPersonOnline bean = new EPersonOnline();
bean.setEmail(email);
bean.setOnlineStatus(true);
return bean;
}
}
@@ -35,11 +35,9 @@ public class TestPersistCascade extends BaseTestCase {
assertThat(sql.get(23)).contains("insert into pcf_city");
assertSqlBind(sql, 24, 26);
assertThat(sql.get(28)).contains("insert into pcf_event");
assertSqlBind(sql, 29, 48);
assertThat(sql.get(50)).contains("insert into pcf_event");
assertSqlBind(sql, 51, 70);
assertThat(sql.get(72)).contains("insert into pcf_event");
assertSqlBind(sql, 73, 87);
assertSqlBind(sql, 29, 128);
assertThat(sql.get(130)).contains("insert into pcf_event");
assertSqlBind(sql, 131, 150);
}
country.deletePermanent();
@@ -1,5 +1,6 @@
package org.tests.level.test;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -19,8 +20,7 @@ public class ManyToManyTest extends BaseTestCase {
@Test
public void test() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Level4 i = new Level4("i");
Level4 ii = new Level4("ii");
Level4 iii = new Level4("iii");
@@ -92,9 +92,6 @@ public class ManyToManyTest extends BaseTestCase {
.findList();
validateObjectGraph(i, ii, iii, one, two, x1, x2, x3, x4, x5, things);
} finally {
DB.endTransaction();
}
}
@@ -39,6 +39,13 @@ public class Product implements Serializable {
@Version
Timestamp updtime;
public Product(Integer id) {
this.id = id;
}
public Product() {
}
/**
* Return id.
*/
@@ -54,7 +54,6 @@ public class TestDeleteUnloadedChildren extends BaseTestCase {
@Test
public void testCascadeDelete2() {
init();
try (Transaction txn = DB.beginTransaction()) {
@@ -68,18 +67,14 @@ public class TestDeleteUnloadedChildren extends BaseTestCase {
@Test
public void testCascadeDelete3() {
init();
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
EdExtendedParent extendedParent = DB.find(EdExtendedParent.class).where()
.eq("name", "My second computer").findOne();
extendedParent.getChildren().size();
DB.delete(extendedParent);
DB.commitTransaction();
} finally {
DB.endTransaction();
txn.commit();
}
}
@@ -49,7 +49,7 @@ public class TestInsertBatchThenFlushThenUpdate extends BaseTestCase {
// nothing flushed yet
assertThat(LoggedSql.start()).isEmpty();
DB.commitTransaction();
txn.commit();
// insert statements for EdExtendedParent
List<String> loggedSql2 = LoggedSql.start();
@@ -44,7 +44,7 @@ public class TestInsertBatchThenUpdate extends BaseTestCase {
parent.setName("MyDesk");
DB.save(parent);
DB.commitTransaction();
txn.commit();
// insert statements for EdExtendedParent
List<String> loggedSql = LoggedSql.stop();
@@ -87,7 +87,7 @@ public class TestInsertBatchThenUpdate extends BaseTestCase {
DB.save(parent);
// flush
DB.commitTransaction();
txn.commit();
// insert statements for EdExtendedParent
List<String> loggedSql = LoggedSql.stop();
@@ -58,7 +58,7 @@ public class TestInsertBatchWithDifferentRootTypes extends BaseTestCase {
// insert statements for EdParent
List<String> loggedSql1 = LoggedSql.start();
DB.commitTransaction();
txn.commit();
assertEquals(0, loggedSql1.size());
@@ -28,6 +28,11 @@ public class OmBeanListChild extends Model {
public Long getId() {
return id;
}
public OmBeanListChild setId(Long id) {
this.id = id;
return this;
}
}
@@ -2,10 +2,14 @@ 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;
@@ -19,6 +23,13 @@ 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;
@@ -35,6 +46,42 @@ 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;
}
}
@@ -1,17 +1,20 @@
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;
public class TestOrphanRemovalOverwrite {
class TestOrphanRemovalOverwrite {
@Test
public void testOverwritingMapping() {
void testOverwritingMapping() {
OmBeanListParent parent = new OmBeanListParent();
parent.save();
@@ -29,8 +32,45 @@ public class TestOrphanRemovalOverwrite {
// Refreshing here generates new objects for the associated children that are referred to by the parent.
parent.refresh();
assertNotNull(childList.get(0).getId());
assertEquals(childList.get(0).getId(), parent.getChildren().get(0).getId());
OmBeanListChild child = childList.get(0);
assertNotNull(child.getId());
OmBeanListChild refreshedChild = parent.getChildren().get(0);
assertEquals(child.getId(), refreshedChild.getId());
assertEquals(child, refreshedChild);
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()");
}
}
@@ -0,0 +1,114 @@
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());
}
}
@@ -1,5 +1,6 @@
package org.tests.persistencecontext;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Database;
@@ -12,12 +13,9 @@ public class TestPersistenceContextOnUpdateDuringTxn extends BaseTestCase {
@Test
public void test() {
Database server = DB.getDefault();
server.beginTransaction();
try {
try (Transaction txn = server.beginTransaction()) {
EBasic bean1 = new EBasic();
bean1.setName("hello");
@@ -33,11 +31,7 @@ public class TestPersistenceContextOnUpdateDuringTxn extends BaseTestCase {
EBasic loadedEntity = server.find(EBasic.class, bean1.getId());
assertThat(loadedEntity.getName()).isEqualTo("hello-changed");
} finally {
server.endTransaction();
}
}
}
@@ -1,5 +1,6 @@
package org.tests.persistencecontext;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -7,25 +8,22 @@ import org.tests.model.basic.EBasicVer;
import static io.ebean.PersistenceContextScope.QUERY;
import static io.ebean.PersistenceContextScope.TRANSACTION;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.*;
public class TestPersistenceContextQueryScope extends BaseTestCase {
class TestPersistenceContextQueryScope extends BaseTestCase {
@Test
public void test() {
void test() {
EBasicVer bean = new EBasicVer("first");
DB.save(bean);
//DB.cacheManager().setCaching(EBasicVer.class, true);
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
EBasicVer bean1 = DB.find(EBasicVer.class, bean.getId());
// do an update of the name in the DB
// With #3295 this now automatically clears the persistence context for BasicVer.class
int rowCount = DB.sqlUpdate("update e_basicver set name=? where id=?")
.setParameter("second")
.setParameter(bean.getId())
@@ -33,22 +31,21 @@ public class TestPersistenceContextQueryScope extends BaseTestCase {
assertEquals(1, rowCount);
// fetch the bean again... but doesn't hit DB as it
// is in the PersistenceContext which is transaction scoped
// Prior to #3295 this returns the same bean via transaction scoped Persistence Context
// With #3295 this is now a fresh bean
EBasicVer bean2 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.findOne();
// QUERY scope hits the DB (doesn't use the existing transactions persistence context)
// ... also explicitly not use bean cache
EBasicVer bean3 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(QUERY)
.findOne();
// TRANsACTION scope ... same as bean2 and does not hit the DB
// TRANSACTION scope ... same as bean2 and does not hit the DB
EBasicVer bean5 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
@@ -57,18 +54,180 @@ public class TestPersistenceContextQueryScope extends BaseTestCase {
assertEquals("first", bean.getName());
assertEquals("first", bean1.getName());
assertEquals("first", bean2.getName());
assertEquals("first", bean5.getName());
assertSame(bean1, bean2);
assertSame(bean1, bean5);
assertEquals("second", bean2.getName());
assertEquals("second", bean3.getName());
assertEquals("second", bean5.getName());
assertNotSame(bean1, bean2);
assertNotSame(bean1, bean5);
assertSame(bean2, bean5);
assertNotSame(bean3, bean5);
DB.delete(bean3);
DB.commitTransaction();
txn.commit();
}
}
} finally {
DB.endTransaction();
@Test
void ormUpdateQuery_expect_clearsContext() {
EBasicVer bean = new EBasicVer("first");
DB.save(bean);
try (Transaction txn = DB.beginTransaction()) {
EBasicVer bean1 = DB.find(EBasicVer.class, bean.getId());
// do an update of the name in the DB
// With #3295 this now automatically clears the persistence context for BasicVer.class
int rowCount = DB.update(EBasicVer.class)
.set("name", "second")
.where().idEq(bean.getId())
.update();
assertEquals(1, rowCount);
// Prior to #3295 this returns the same bean via transaction scoped Persistence Context
// With #3295 this is now a fresh bean
EBasicVer bean2 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.findOne();
// QUERY scope hits the DB (doesn't use the existing transactions persistence context)
EBasicVer bean3 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(QUERY)
.findOne();
// TRANSACTION scope ... same as bean2 and does not hit the DB
EBasicVer bean5 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(TRANSACTION)
.findOne();
assertEquals("first", bean.getName());
assertEquals("first", bean1.getName());
assertEquals("second", bean2.getName());
assertEquals("second", bean3.getName());
assertEquals("second", bean5.getName());
assertNotSame(bean1, bean2);
assertNotSame(bean1, bean5);
assertSame(bean2, bean5);
assertNotSame(bean3, bean5);
DB.delete(bean3);
txn.commit();
}
}
@Test
void ormUpdate_expect_clearsContext() {
EBasicVer bean = new EBasicVer("first");
DB.save(bean);
try (Transaction txn = DB.beginTransaction()) {
EBasicVer bean1 = DB.find(EBasicVer.class, bean.getId());
// do an update of the name in the DB
// With #3295 this now automatically clears the persistence context for BasicVer.class
int rowCount = DB.createUpdate(EBasicVer.class, "update ebasicver set name = ? where id = ?")
.setParameter(1, "second")
.setParameter(2, bean.getId())
.execute();
assertEquals(1, rowCount);
// fetch the bean again...
// Prior to #3295 this returns the same bean via transaction scoped Persistence Context
// With #3295 this is now a fresh bean
EBasicVer bean2 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.findOne();
// QUERY scope hits the DB (doesn't use the existing transactions persistence context)
EBasicVer bean3 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(QUERY)
.findOne();
// TRANSACTION scope ... same as bean2 and does not hit the DB
EBasicVer bean5 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(TRANSACTION)
.findOne();
assertEquals("first", bean.getName());
assertEquals("first", bean1.getName());
assertEquals("second", bean2.getName());
assertEquals("second", bean3.getName());
assertEquals("second", bean5.getName());
assertNotSame(bean1, bean2);
assertNotSame(bean1, bean5);
assertSame(bean2, bean5);
assertNotSame(bean3, bean5);
DB.delete(bean3);
txn.commit();
}
}
@Test
void ormUpdateQueryWithAutoPersist_expect_clearsContext() {
EBasicVer bean = new EBasicVer("first");
DB.save(bean);
try (Transaction txn = DB.beginTransaction()) {
txn.setAutoPersistUpdates(true);
EBasicVer bean1 = DB.find(EBasicVer.class, bean.getId());
// do an update of the name in the DB
// With #3295 this now automatically clears the persistence context for BasicVer.class
int rowCount = DB.update(EBasicVer.class)
.set("name", "second")
.where().idEq(bean.getId())
.update();
assertEquals(1, rowCount);
// Prior to #3295 this returns the same bean via transaction scoped Persistence Context
// With #3295 this is now a fresh bean
EBasicVer bean2 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.findOne();
// QUERY scope hits the DB (doesn't use the existing transactions persistence context)
EBasicVer bean3 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(QUERY)
.findOne();
// TRANSACTION scope ... same as bean2 and does not hit the DB
EBasicVer bean5 = DB.find(EBasicVer.class)
.setId(bean.getId())
.setUseCache(false) // ignore L2 cache
.setPersistenceContextScope(TRANSACTION)
.findOne();
assertEquals("first", bean.getName());
assertEquals("first", bean1.getName());
assertEquals("first", bean2.getName()); // This is still first
assertEquals("second", bean3.getName());
assertEquals("first", bean5.getName()); // This is still first
assertSame(bean1, bean2); // Now the same
assertSame(bean1, bean5); // Now the same
assertSame(bean2, bean5);
assertNotSame(bean3, bean5);
DB.delete(bean3);
txn.commit();
}
}
}
@@ -1,5 +1,6 @@
package org.tests.query;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Query;
@@ -50,23 +51,18 @@ public class TestConnectionCloseOnSqlerr extends BaseTestCase {
try {
for (int i = 0; i < 100; i++) {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Query<Customer> q0 = DB.find(Customer.class).where().icontains("namexxx", "Rob")
.query();
q0.findList();
DB.commitTransaction();
txn.commit();
} catch (Exception e) {
if (e.getMessage().contains("Unsuccessfully waited")) {
fail("No connections found while only one thread is running. (after " + i + " queries)");
} else {
e.printStackTrace();
}
} finally {
if (DB.currentTransaction().isActive()) {
DB.rollbackTransaction();
}
}
}
@@ -6,11 +6,87 @@ 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,6 +11,7 @@ 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;
@@ -218,8 +219,7 @@ public class TestQueryFindPagedList extends BaseTestCase {
// kinda not normal but just wrap in a transaction to assert
// the background fetch does not occur (which explicitly creates
// its own transaction) ... so a bit naughty with the test here
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
List<Order> orders = pagedList.getList();
int totalRowCount = pagedList.getTotalCount();
@@ -237,13 +237,9 @@ public class TestQueryFindPagedList extends BaseTestCase {
String secTxn = loggedSql.get(1).substring(0, 10);
assertEquals(firstTxn, secTxn);
} finally {
DB.endTransaction();
}
}
@Test
public void test_usingAlias() {
@@ -269,23 +265,25 @@ public class TestQueryFindPagedList extends BaseTestCase {
@Test
void test_forUpdate() {
ResetBasicData.reset();
if (!isDb2()) {
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;");
}
}
}
}
@@ -84,15 +84,10 @@ public class TestCustomerFinder extends BaseTestCase {
@Test
public void currentTransaction() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Transaction t1 = DB.currentTransaction();
Transaction t2 = Customer.find.currentTransaction();
assertThat(t2).isSameAs(t1);
} finally {
DB.endTransaction();
}
}
@@ -1,9 +1,10 @@
package org.tests.query.joins;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Expr;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.basic.one2one.Wheel;
import org.tests.model.basic.MRole;
@@ -18,8 +19,7 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase {
@Test
public void test() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
MRole r1 = new MRole();
r1.setRoleName("role1B");
@@ -63,8 +63,6 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase {
assertSqlOuterJoins(sql);
assertThat(sql).contains(".role_name = ?");
} finally {
DB.rollbackTransaction();
}
}
@@ -76,7 +74,7 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase {
.eq("roles.roleid", roleid)
.endOr().query();
query.findList();
query.findList();
String sql = sqlOf(query);
assertSqlOuterJoins(sql);
@@ -85,19 +83,16 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase {
@Test
public void testSelectOneToOneDisjunction() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Query<Wheel> query = DB.find(Wheel.class)
.select("id")
.where().or()
.ge("tire.id", 100)
.lt("tire.id", 100)
.endOr().query();
.select("id")
.where().or()
.ge("tire.id", 100)
.lt("tire.id", 100)
.endOr().query();
query.findList();
String sql = sqlOf(query);
assertThat(sql).contains("join");
} finally {
DB.rollbackTransaction();
}
}
@@ -1,5 +1,6 @@
package org.tests.query.other;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebeaninternal.api.SpiEbeanServer;
@@ -44,8 +45,7 @@ public class TestManyLazyLoadingQuery extends BaseTestCase {
// start transaction to keep PC going to lazy query
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.find(Order.class, 1);
SpiQuery<?> query0 = (SpiQuery<?>) DB.find(OrderDetail.class);
@@ -57,9 +57,6 @@ public class TestManyLazyLoadingQuery extends BaseTestCase {
query0.findList();
assertThat(query0.getGeneratedSql()).contains(" from o_order_detail t0 where (t0.order_id) ");
platformAssertIn(query0.getGeneratedSql(), "where (t0.order_id)");
} finally {
DB.endTransaction();
}
List<OrderDetail> details = DB.find(OrderDetail.class)
@@ -62,8 +62,7 @@ public class TestBatchPersistCascade extends BaseTestCase {
List<UTMaster> list = server.find(UTMaster.class).fetch("details").findList();
Transaction txn = server.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
txn.setBatchMode(true);
txn.setBatchOnCascade(true);
@@ -103,11 +102,8 @@ public class TestBatchPersistCascade extends BaseTestCase {
logger.info("commit ------------ ");
server.commitTransaction();
} finally {
server.endTransaction();
txn.commit();
}
}
private UTDetail createUTDetail(String master, int count) {
@@ -1,5 +1,6 @@
package org.tests.transaction;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebeaninternal.api.SpiTransaction;
@@ -19,9 +20,8 @@ public class TestDeleteFromPersistenceContext extends BaseTestCase {
EBasicVer bean = new EBasicVer("Please Delete Me");
DB.save(bean);
SpiTransaction transaction = (SpiTransaction) DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
SpiTransaction spiTransaction = (SpiTransaction)txn;
EBasicVer bean2 = DB.find(EBasicVer.class, bean.getId());
assertNotSame(bean, bean2);
@@ -29,18 +29,15 @@ public class TestDeleteFromPersistenceContext extends BaseTestCase {
// same instance from PersistenceContext
assertSame(bean2, bean3);
Object bean4 = transaction.persistenceContext().get(EBasicVer.class, bean.getId());
Object bean4 = spiTransaction.persistenceContext().get(EBasicVer.class, bean.getId());
assertSame(bean2, bean4);
DB.delete(bean2);
Object bean5 = transaction.persistenceContext().get(EBasicVer.class, bean.getId());
Object bean5 = spiTransaction.persistenceContext().get(EBasicVer.class, bean.getId());
assertNull(bean5);
DB.commitTransaction();
} finally {
DB.endTransaction();
txn.commit();
}
EBasicVer bean6 = DB.find(EBasicVer.class).where().eq("id", bean.getId()).findOne();
@@ -1,11 +1,14 @@
package org.tests.transaction;
import io.ebean.*;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.ForPlatform;
import io.ebean.DB;
import io.ebean.DataIntegrityException;
import io.ebean.Transaction;
import io.ebean.TxScope;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.annotation.Transactional;
import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.ForPlatform;
import io.ebeaninternal.api.SpiTransaction;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
@@ -43,7 +46,7 @@ public class TestExecuteComplete extends BaseTestCase {
try {
DB.execute(TxScope.required().setBatch(PersistBatch.ALL), () ->
DB.execute(() -> {
DB.execute(() -> {
Customer customer = DB.reference(Customer.class, 42424242L);
Order order = new Order();
@@ -158,4 +161,26 @@ public class TestExecuteComplete extends BaseTestCase {
assertThat(getInScopeTransaction()).isNull();
}
@ForPlatform(Platform.H2)
@Test
public void test_nested_userobjects() {
try (Transaction txn1 = DB.beginTransaction()) {
assertThat(getInScopeTransaction()).isNotNull();
getInScopeTransaction().putUserObject("foo", "bar");
try (Transaction txn2 = DB.beginTransaction()) {
assertThat(getInScopeTransaction().getUserObject("foo")).isEqualTo("bar");
getInScopeTransaction().putUserObject("foo", "xxx");
getInScopeTransaction().putUserObject("test", "xxx");
assertThat(getInScopeTransaction().getUserObject("foo")).isEqualTo("xxx");
txn2.commit();
}
// CHECKME: What would we expect here? I would expect "bar" but get "xxx"
// NOTE: with TxScope.requiresNew() - I'll get "bar"
assertThat(getInScopeTransaction().getUserObject("test")).isNull();
assertThat(getInScopeTransaction().getUserObject("foo")).isEqualTo("bar");
}
}
}
@@ -37,8 +37,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
try (Transaction txn1 = server.beginTransaction()) {
bean.setName("x2");
server.save(bean);
//txn1.commit();
server.commitTransaction();
txn1.commit();
}
EBasic fresh = server.find(EBasic.class, bean.getId());
@@ -48,8 +47,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
try (Transaction txn2 = server.beginTransaction()) {
bean.setName("barney");
DB.save(bean);
//txn2.commit();
server.commitTransaction();
txn2.commit();
}
fresh = server.find(EBasic.class)
@@ -1,5 +1,6 @@
package org.tests.transaction;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -12,10 +13,7 @@ public class TestStatelessUpdateClearPC extends BaseTestCase {
@Test
public void test() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
EBasic newUser = new EBasic();
newUser.setName("any@email.com");
DB.save(newUser);
@@ -32,8 +30,6 @@ public class TestStatelessUpdateClearPC extends BaseTestCase {
EBasic loadedUser = DB.find(EBasic.class, newUser.getId());
assertEquals("anyNew@email.com", loadedUser.getName());
} finally {
DB.rollbackTransaction();
}
}
}
@@ -31,11 +31,8 @@ public class TestTransactionCallback extends BaseTestCase {
assertEquals(0, countPreRollback);
assertEquals(0, countPostRollback);
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.register(new MyCallback());
} finally {
DB.rollbackTransaction();
}
assertEquals(1, countPreCommit);
@@ -32,8 +32,7 @@ public class TestTransactionalNotSupports extends BaseTestCase {
public void withOuterTransaction_expect_currentTransaction_null_and_originalTxnRestored() {
outerTxn = null;
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
currentTxn = DB.currentTransaction();
assertNotNull(currentTxn);
new SomeTransactionalWithNotSupported().doStuff();
@@ -44,8 +43,6 @@ public class TestTransactionalNotSupports extends BaseTestCase {
// the original transaction was restored
Transaction restored = DB.currentTransaction();
assertSame(currentTxn, restored);
} finally {
DB.endTransaction();
}
}
@@ -40,8 +40,7 @@ public class TestTransactionalRequired extends BaseTestCase {
public void withOuterBegin() {
outerTxn = null;
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
currentTxn = DB.currentTransaction();
assertNotNull(currentTxn);
new OuterTransactionalWithRequired().doOuter();
@@ -51,8 +50,6 @@ public class TestTransactionalRequired extends BaseTestCase {
assertSame(currentTxn, restored);
assertSame(currentTxn, innerTxn);
assertSame(currentTxn, outerTxn);
} finally {
DB.endTransaction();
}
assertNull(DB.currentTransaction());
@@ -68,11 +68,8 @@ public class TestTransactionalRequiresNew extends BaseTestCase {
Database server = server();
try(Transaction txn = server.beginTransaction()) {
String txnName = txn.toString();
DB.beginTransaction(TxScope.requiresNew());
try {
DB.commitTransaction();
} finally {
DB.endTransaction();
try (Transaction txn2 = DB.beginTransaction(TxScope.requiresNew())) {
txn2.commit();
}
assertThat(txn.toString()).isEqualTo(txnName);
}
@@ -83,11 +80,8 @@ public class TestTransactionalRequiresNew extends BaseTestCase {
Database server = server();
try (Transaction txn = server.beginTransaction()) {
String txnName = txn.toString();
server.beginTransaction(TxScope.requiresNew());
try {
server.commitTransaction();
} finally {
server.endTransaction();
try (Transaction txn2 = server.beginTransaction(TxScope.requiresNew())) {
txn2.commit();
}
assertThat(txn.toString()).isEqualTo(txnName);
}
@@ -98,11 +92,8 @@ public class TestTransactionalRequiresNew extends BaseTestCase {
Database server = server();
try (Transaction txn = server.beginTransaction()) {
String txnName = txn.toString();
Transaction txn2 = DB.beginTransaction(TxScope.requiresNew());
try {
try (Transaction txn2 = DB.beginTransaction(TxScope.requiresNew())) {
txn2.commit();
} finally {
txn2.end();
}
assertThat(txn.toString()).isEqualTo(txnName);
}

Some files were not shown because too many files have changed in this diff Show More