Compare commits

..
Author SHA1 Message Date
Rob Bygrave 714bbadbc0 [maven-release-plugin] prepare release ebean-parent-13.11.4 2023-02-13 13:34:14 +13:00
Rob Bygrave 9e811e9aef bump ebean-agent to 13.11.4 2023-02-13 13:25:33 +13:00
Rob Bygrave f97dcb60c0 Improve test only, QCustomerTest using AttributeConverter 2023-02-13 08:08:16 +13:00
Rob Bygrave 65c76cb2c0 Fix test to support SqlServer using sequences 2023-02-10 14:22:11 +13:00
Rob Bygrave 874427dac1 Fix test to also support Postgres ANY 2023-02-10 14:19:35 +13:00
Rob BygraveandGitHub 1176c2e97a Merge pull request #2962 from ebean-orm/feature/2961
#2961 - Followup for #2952 - @OneToMany + orphanRemoval + @SoftDelete + non-BeanCollection collection results in hard deletes
2023-02-10 13:10:01 +13:00
Rob Bygrave 44e0585fb7 #2961 - Followup for #2952 - @OneToMany + orphanRemoval + @SoftDelete + non-BeanCollection collection results in hard deletes
As noted in comments in #2952

In the internals of SaveManyBeans we have:

- BUG: the deleteByParentId is hard delete and does not care for soft delete
- YUK: internally we have 3 ways of performing the orphan removal when we really want 2

This change fixes the BUG and fixes the YUK. It does this by removing the special case at: https://github.com/ebean-orm/ebean/blob/ebean-parent-13.11.3/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java#L347-L350 ... and replacing it with the more common orphan removal code used when we do not have BeanCollection modifications.

The result of this change is that in SaveManyBeans internals we get back to have 2 ways to remove orphans.

- A BeanCollection with modifications: Orphans explicitly deleted using the known elements removed from the collection
- All other cases: Orphans as everything NOT in the collection that is going to be updated
2023-02-10 13:08:44 +13:00
Rob BygraveandGitHub 889c0f12e0 Merge pull request #2960 from ebean-orm/buchtajz-one2many_setArraylist
Fix for @OneToMany orphanRemoval not occurring for #2952 #2953
2023-02-10 13:01:55 +13:00
Rob Bygrave 0135263dbd Style only for SaveManyBeans switching order in if/else 2023-02-09 23:45:27 +13:00
Rob Bygrave 564194042b No effective change, BeanCollectionUtil perform the instanceof Collection before instanceof Map check 2023-02-09 23:44:13 +13:00
Rob Bygrave 244d45674a #2952 #2953 - Fix for @OneToMany orphanRemoval not occurring
orphanRemoval was not occurring when a loaded bean had a collection
replaced by a new BeanCollection (as opposed to a vanilla collection
like java.util.ArrayList).

Json marshalling a collection puts beans into BeanCollection and this
is part of the test that reproduced this issue.
2023-02-09 23:29:13 +13:00
Rob Bygrave 4722f10f5e Bump versions after release 2023-02-07 22:46:08 +13:00
Rob Bygrave 3f5140e7f3 [maven-release-plugin] prepare for next development iteration 2023-02-07 22:10:29 +13:00
Rob Bygrave 43dec17d08 [maven-release-plugin] prepare release ebean-parent-13.11.3 2023-02-07 22:10:16 +13:00
Rob Bygrave f1ee45d7d1 Bump ebean-agent to 13.11.3 2023-02-07 22:06:16 +13:00
Rob Bygrave 3263e7bfc3 #2959 - Improve logging for lazy loading error due to "markAsDeleted" 2023-02-07 22:05:34 +13:00
Rob Bygrave e01f19b3aa Merge branch 'one2many_setArraylist' of github.com:buchtajz/ebean into buchtajz-one2many_setArraylist 2023-02-07 20:09:01 +13:00
Rob Bygrave 20f6a659fe #2959 - Improve logging for lazy loading error due to "markAsDeleted" 2023-02-07 19:59:33 +13:00
Michal Buchtík 09fe923770 Merge remote-tracking branch 'origin/one2many_setArraylist' into one2many_setArraylist 2023-02-05 09:28:11 +01:00
buchtajzandGitHub e6f5e42c2d Merge branch 'ebean-orm:master' into one2many_setArraylist 2023-02-05 09:25:29 +01:00
Rob Bygrave 5150ecba62 #2948 - SoftDelete entities are hard deleted on orphan removal 2023-02-02 23:15:22 +13:00
Rob Bygrave 978b1dbe02 Merge branch 'master' of github.com:ebean-orm/ebean 2023-02-02 23:06:49 +13:00
Rob Bygrave 9813703ce5 Merge branch 'Ichtil-hard_delete_instead_of_soft_delete_2' 2023-02-02 23:03:28 +13:00
Rob Bygrave 09001e80b5 #2948 - SoftDelete entities are hard deleted on orphan removal 2023-02-02 23:02:44 +13:00
Rob BygraveandGitHub 4aa3ca6d95 Merge pull request #2941 from FOCONIS/expressionlist-clear
NEW: ExpressionList has clear() method
2023-02-02 01:13:28 +13:00
Rob BygraveandGitHub 5ec8469ddc Merge pull request #2940 from FOCONIS/fix-bom
FIX: Removed non existent modules from BOM
2023-02-02 00:42:43 +13:00
Michal Buchtík 39099bbcc9 print sql 2023-01-31 23:01:52 +01:00
Michal Buchtík cb2ca0de11 setArrayListDoInsertInsteadUpdate 2023-01-30 23:47:18 +01:00
Jan Klička b25233b0b9 Merge branch 'master' into hard_delete_instead_of_soft_delete_2
# Conflicts:
#	ebean-test/pom.xml
2023-01-27 16:28:03 +01:00
Jan Klička 743f1b10e3 #2948 2023-01-27 16:17:01 +01:00
Roland Praml 371f50fb4d NEW: ExpressionList has clear() method 2023-01-23 11:33:29 +01:00
Roland Praml a3be2041c8 FIX: Removed non existent modules from BOM 2023-01-23 11:31:45 +01:00
Rob Bygrave 09a831f2d6 Bump versions after release 2023-01-21 22:35:40 +13:00
Rob Bygrave 27d9e03691 [maven-release-plugin] prepare for next development iteration 2023-01-21 20:37:02 +13:00
Rob Bygrave 5a3c6b9dad [maven-release-plugin] prepare release ebean-parent-13.11.2 2023-01-21 20:36:54 +13:00
Rob Bygrave 502eb78ffd Bump ebean-agent to 13.11.2 2023-01-21 20:25:49 +13:00
Rob Bygrave 761ec584b2 #2939 - [yugabyte] Bump testing against Yugabyte to use version 2.16.0.1-b7 2023-01-20 18:01:53 +13:00
Rob Bygrave 144b8c3077 #2939 - [yugabyte] Bump testing against Yugabyte to use version 2.16.0.1-b7 2023-01-20 17:35:27 +13:00
Rob Bygrave 79a1b3a024 Merge branch 'master' of github.com:ebean-orm/ebean 2023-01-20 16:58:41 +13:00
Rob Bygrave 519b75a778 Adjust tests for Postgres - DtoQuery2Test and EaObject 2023-01-20 16:58:26 +13:00
Rob BygraveandGitHub 1659c526d7 Merge pull request #2938 from FOCONIS/scan-cache-annotations-recursively
FIX: Search cache annotations recursively
2023-01-20 09:35:54 +13:00
Rob Bygrave 93fc7b07a0 Add more tests for DtoQuery column -> property mapping 2023-01-20 09:32:38 +13:00
Rob BygraveandGitHub d7e6feebc2 Merge pull request #2935 from ebean-orm/feature/2915-invalid-id-mapping
#2915 - Failing test for - generator param of @GeneratedValue is not ignored when using GenerationType.AUTO on db where this uses identity
2023-01-20 08:34:25 +13:00
Rob Bygrave 2a6c60c89b #2915 - Fix for generator param of @GeneratedValue is not ignored when using GenerationType.AUTO on db where this uses identity 2023-01-20 08:27:09 +13:00
Roland Praml b569ec97ee FIX: Search cache annotations recursively 2023-01-19 16:22:38 +01:00
Rob Bygrave 6b6cf48ae2 Merge branch 'FOCONIS-fix-order-by-on-prop' 2023-01-18 07:52:58 +13:00
Rob Bygrave f09cba3ab5 #2930 - Add extra test for DbOrderByTrimTest 2023-01-18 07:52:43 +13:00
Rob Bygrave 724183f669 Merge branch 'fix-order-by-on-prop' of github.com:FOCONIS/ebean into FOCONIS-fix-order-by-on-prop 2023-01-18 07:46:41 +13:00
Rob BygraveandGitHub a40212d41e Merge pull request #2934 from ebean-orm/feature/2931-redis-collectionIds
Ebean Redis - Failed to decode cache data for UUID as Id
2023-01-18 07:41:59 +13:00
Rob BygraveandGitHub c9ce02c43d Merge pull request #2933 from FOCONIS/bugfix/drop_table_drop_foreign_keys
Drop table statements potentially not possible due to foreign key constraints
2023-01-18 07:41:38 +13:00
Rob Bygrave 03c9782d63 #2915 - Failing test for - generator param of @GeneratedValue is not ignored when using GenerationType.AUTO on db where this uses identity 2023-01-18 00:07:04 +13:00
Rob Bygrave 130e9451f4 #2931 - Fix for Ebean Redis - Failed to decode cache data for UUID as Id 2023-01-17 23:20:33 +13:00
Rob Bygrave dce6a3e9e1 #2931 - Failing test for Ebean Redis - Failed to decode cache data for UUID as Id 2023-01-17 23:10:08 +13:00
Rob BygraveandGitHub 486044d29b Merge pull request #2932 from parveenyadav-multiply/patch-2
Create UUIDAsIDModel.java
2023-01-17 20:51:45 +13:00
parveenyadav-multiplyandGitHub 934b0f0044 Create UUIDAsIDModel.java 2023-01-16 03:05:01 +05:30
Jonas Pöhler 2633cd6bfe FIX: drop foreign keys before dropping tables 2023-01-13 15:35:54 +01:00
Jonas Pöhler 2c81d0df03 ADD: failing testcase for dropping two or more related, but otherwise unreferenced tables 2023-01-13 15:14:35 +01:00
Roland Praml 9ef59e359b Removed supportsSelect (dead code) 2023-01-13 13:43:41 +01:00
Roland Praml 6561f6f5e7 BUG: @OrderBy on chained properties do not work with distinct (fix) 2023-01-13 13:29:16 +01:00
Roland Praml b2e8e628fa BUG: @OrderBy on chained properties do not work with distinct (testcase) 2023-01-13 13:06:54 +01:00
Rob Bygrave bbb8d85971 Fix test TestBeanCache for postgres compatible asserts 2023-01-10 20:17:50 +13:00
Rob Bygrave 14b94ebe12 Bump to 13.11.2-SNAPSHOT 2023-01-09 11:09:00 +13:00
Rob Bygrave f5f59d90d4 [maven-release-plugin] prepare for next development iteration 2023-01-09 10:45:37 +13:00
Rob Bygrave ac3f4ca369 [maven-release-plugin] prepare release ebean-parent-13.11.1 2023-01-09 10:45:29 +13:00
Rob Bygrave 10133e6040 Bump agent to 13.11.1 2023-01-09 10:40:40 +13:00
Rob BygraveandGitHub 321fb26df3 Merge pull request #2927 from FOCONIS/findset-beancache
NEW: BeanCache for findSet
2023-01-09 10:29:15 +13:00
Rob BygraveandGitHub 28bd018d1f Merge pull request #2926 from FOCONIS/prepare-query
FIX: prepare FindMap query for proper bean cache / DB access
2023-01-09 10:28:09 +13:00
Rob BygraveandGitHub cceb29313b Merge pull request #2928 from ebean-orm/feature/2918-findEach-EmbeddedId-Memory
Fix memory leak with streaming queries with Id Embedded
2023-01-09 10:25:39 +13:00
Rob Bygrave 530bfa982e Fix memory leak with streaming queries with Id Embedded
- The Id Embedded beans do not need the embeddedOwner to be set. They do not need to propagate dirty state back to the owner.
2023-01-05 23:27:22 +13:00
Rob BygraveandGitHub 3cfa636e88 Merge pull request #2925 from FOCONIS/exclude-from-cp-scan
Ignore private/package private classes from CP-scan / FIX: Order of runServerConfigStartup
2023-01-05 20:16:40 +13:00
Roland Praml a2e8f098cf NEW: BeanCache for findSet 2023-01-04 17:11:24 +01:00
Roland Praml 9e42cfd7d7 FIX: prepare FindMap query for proper bean cache access 2023-01-04 16:59:31 +01:00
Roland Praml a3c54d4d20 FIX: Order of runServerConfigStartup 2023-01-04 14:00:16 +01:00
Roland Praml 1d48e2afb3 Ignore private/package private classes from CP-scan 2023-01-04 13:59:51 +01:00
Rob Bygrave d84c9dc1a9 Bump versions in test modules after release 2022-12-08 18:00:24 +13:00
Rob Bygrave 6165bf5a6c Bump versions in test modules after release 2022-12-08 17:06:41 +13:00
Rob Bygrave 712d3ea78f [maven-release-plugin] prepare for next development iteration 2022-12-08 15:31:04 +13:00
Rob Bygrave 96e3c95c29 [maven-release-plugin] prepare release ebean-parent-13.11.0 2022-12-08 15:30:51 +13:00
Rob Bygrave e6e25b979f Bump to 13.11.0-SNAPSHOT 2022-12-08 15:21:16 +13:00
Rob Bygrave 50fd0f6b1a Bump ebean-agent to 13.11.0 2022-12-08 15:19:30 +13:00
Rob Bygrave 0e9b83a1ce #2914 - Refactor ProcessingContext.getPropertyType() internals and whitespace 2022-12-08 11:37:10 +13:00
Rob Bygrave d2f629e7bb #2914 - Query bean generation support for @ElementCollection with validaiton annotations - NPE NullPointerException 2022-12-08 11:10:23 +13:00
Rob Bygrave e290f68b29 Revert "#2908 - Fix tests for Oracle and DB2 with maxRows and forUpdate() 2022-12-01 22:58:30 +13:00
Rob Bygrave a17e62b491 Revert "#2908 - [Oracle] Change OraclePlatform to use AnsiSqlLimiter (noting Oracle does not support FOR UPDATE with FETCH/OFFSET"
This reverts commit 62ed5a9f
2022-12-01 22:51:37 +13:00
Rob Bygrave 928db1f0f6 #2909 - [Hana] Replace HanaSqlLimitSqlLimiter with standard LimitOffsetSqlLimiter 2022-12-01 22:42:42 +13:00
Rob Bygrave c317092dc5 #2907 - Promote Db2SqlLimiter to be AnsiSqlRowsLimiter and move to ebean-api module 2022-12-01 22:40:13 +13:00
Rob Bygrave 95512d4851 #2906 - Tidy LimitOffsetSqlLimiter 2022-12-01 22:27:57 +13:00
Rob Bygrave 62ed5a9f2b #2908 - [Oracle] Change OraclePlatform to use AnsiSqlLimiter (noting Oracle does not support FOR UPDATE with FETCH/OFFSET 2022-12-01 22:24:35 +13:00
Rob Bygrave 37ba0b63e4 #2907 - Promote Db2SqlLimiter to be AnsiSqlRowsLimiter and move to ebean-api module 2022-12-01 22:18:16 +13:00
Rob Bygrave 22a5bd9b9d #2906 - Refactor tidy SqlLimiter implementations 2022-12-01 21:39:00 +13:00
Rob Bygrave 45529958ef #2904 MySql and MariaDB do not support OFFSET without LIMIT, ignore them for these tests 2022-12-01 21:27:44 +13:00
Rob Bygrave 7aa64f47c8 Fix test TestQueryCache for Oracle (not supporting READ_UNCOMMITTED as expected) 2022-12-01 10:46:26 +13:00
Rob BygraveandGitHub 919adf331a Merge pull request #2866 from FOCONIS/fix-formula-match-base-platform
FIX: @Formula / @Where Annotations should also match on base platform
2022-12-01 08:56:13 +13:00
Rob BygraveandGitHub 9f229e3cc2 Merge pull request #2904 from serg1236/bugfix/offset_without_limit
Fixed mandatory LIMIT generation in case of firstRow>0
2022-12-01 08:45:18 +13:00
Serhii Dakhnii 3277fe81a1 Fixed mandatory LIMIT generation in case of firstRow>0 2022-11-30 21:36:08 +02:00
Rob BygraveandGitHub 6c6ec3663a Merge pull request #2896 from ebean-orm/dependabot/maven/ebean-core/org.postgresql-postgresql-42.5.1
Bump postgresql from 42.5.0 to 42.5.1 in /ebean-core
2022-11-24 11:40:45 +13:00
Rob BygraveandGitHub 0461580d1c Merge pull request #2897 from ebean-orm/dependabot/maven/ebean-test/org.postgresql-postgresql-42.5.1
Bump postgresql from 42.5.0 to 42.5.1 in /ebean-test
2022-11-24 11:40:28 +13:00
Rob BygraveandGitHub 75dbb58c85 Merge pull request #2898 from ebean-orm/dependabot/maven/ebean-postgis/org.postgresql-postgresql-42.5.1
Bump postgresql from 42.5.0 to 42.5.1 in /ebean-postgis
2022-11-24 11:40:09 +13:00
Rob BygraveandGitHub 808f69cac1 Merge pull request #2899 from ebean-orm/dependabot/maven/platforms/postgres/org.postgresql-postgresql-42.5.1
Bump postgresql from 42.5.0 to 42.5.1 in /platforms/postgres
2022-11-24 11:39:52 +13:00
Rob BygraveandGitHub 974953a376 Merge pull request #2900 from ebean-orm/dependabot/maven/ebean-core-type/org.postgresql-postgresql-42.4.3
Bump postgresql from 42.4.1 to 42.4.3 in /ebean-core-type
2022-11-24 11:38:55 +13:00
dependabot[bot]andGitHub f85a367e98 Bump postgresql from 42.4.1 to 42.4.3 in /ebean-core-type
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.4.1 to 42.4.3.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.4.1...REL42.4.3)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 22:27:09 +00:00
dependabot[bot]andGitHub 87a3c58d93 Bump postgresql from 42.5.0 to 42.5.1 in /platforms/postgres
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.0 to 42.5.1.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.0...REL42.5.1)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 22:24:12 +00:00
dependabot[bot]andGitHub 1d1aea77d0 Bump postgresql from 42.5.0 to 42.5.1 in /ebean-test
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.0 to 42.5.1.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.0...REL42.5.1)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 22:21:01 +00:00
dependabot[bot]andGitHub 2a02935cee Bump postgresql from 42.5.0 to 42.5.1 in /ebean-postgis
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.0 to 42.5.1.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.0...REL42.5.1)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 22:21:01 +00:00
dependabot[bot]andGitHub fd2e5c0fc7 Bump postgresql from 42.5.0 to 42.5.1 in /ebean-core
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.0 to 42.5.1.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.0...REL42.5.1)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-23 22:21:00 +00:00
Rob Bygrave 6d6b07bf87 Bump avaje-config to version 2.4 2022-11-23 08:35:04 +13:00
Rob Bygrave 2cac3cd0bb Bump test modules to 13.10.3-SNAPSHOT after release 2022-11-22 08:26:56 +13:00
Rob Bygrave d56098dbf0 [maven-release-plugin] prepare for next development iteration 2022-11-22 08:09:45 +13:00
Roland Praml 359f8b41fe FIX: @Formula / @Where Annotations should also match on base platform
A property annotated with
```java
@Formula(select = "...", platforms = SQLSERVER)
```
should match for SQLSERVER17 and SQLSERVER19
2022-10-25 10:55:23 +02:00
257 changed files with 3081 additions and 785 deletions
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+9 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,31 +16,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -53,18 +53,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>composites</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean api</name>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>2.2</version>
<version>2.4</version>
</dependency>
<!--
@@ -1730,4 +1730,8 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> endNot();
/**
* Clears the current expression list.
*/
ExpressionList<T> clear();
}
@@ -231,18 +231,6 @@ public class OrderBy<T> implements Serializable {
return this;
}
/**
* Return true if this order by can be used in select clause.
*/
public boolean supportsSelect() {
for (Property property : list) {
if (!property.supportsSelect()) {
return false;
}
}
return true;
}
/**
* A property and its ascending descending order.
*/
@@ -403,12 +391,6 @@ public class OrderBy<T> implements Serializable {
this.ascending = ascending;
}
/**
* Support use in select clause if no collation or nulls ordering.
*/
boolean supportsSelect() {
return nulls == null;
}
}
private void parse(String orderByClause) {
@@ -725,7 +725,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
loader.loadBean(this);
if (lazyLoadFailure) {
// failed when lazy loading this bean
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted.");
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
}
// bean should be loaded and intercepting now. setLoaded() has
// been called by the lazy loading mechanism
@@ -1,20 +1,16 @@
package io.ebean.platform.db2;
package io.ebean.config.dbplatform;
import io.ebean.config.dbplatform.SqlLimitRequest;
import io.ebean.config.dbplatform.SqlLimitResponse;
import io.ebean.config.dbplatform.SqlLimiter;
public class Db2SqlLimiter implements SqlLimiter {
public final class AnsiSqlRowsLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
StringBuilder sb = new StringBuilder(512);
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(request.getDbSql());
sb.append(dbSql);
int firstRow = request.getFirstRow();
if (firstRow > 0) {
sb.append(" offset ").append(firstRow).append(" rows");
@@ -23,7 +19,6 @@ public class Db2SqlLimiter implements SqlLimiter {
if (maxRows > 0) {
sb.append(" fetch next ").append(maxRows).append(" rows only");
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
@@ -3,42 +3,25 @@ package io.ebean.config.dbplatform;
/**
* Adds LIMIT OFFSET clauses to a SQL query.
*/
public class LimitOffsetSqlLimiter implements SqlLimiter {
/**
* LIMIT keyword.
*/
private static final String LIMIT = "limit";
/**
* OFFSET keyword.
*/
private static final String OFFSET = "offset";
public final class LimitOffsetSqlLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
int firstRow = request.getFirstRow();
int maxRows = request.getMaxRows();
if (maxRows > 0 || firstRow > 0) {
sb.append(" ").append(LIMIT).append(" ").append(maxRows);
if (firstRow > 0) {
sb.append(" ").append(OFFSET).append(" ");
sb.append(firstRow);
}
if (maxRows > 0) {
sb.append(" limit ").append(maxRows);
}
int firstRow = request.getFirstRow();
if (firstRow > 0) {
sb.append(" offset ").append(firstRow);
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
@@ -5,14 +5,6 @@ package io.ebean.config.dbplatform;
*/
public interface SqlLimiter {
/**
* the new line character used.
* <p>
* Note that this is removed for logging sql to the transaction log.
* </p>
*/
char NEW_LINE = '\n';
/**
* Add the SQL limiting statements around the query.
*/
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
@@ -55,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
+30 -48
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean bom</name>
@@ -89,192 +89,174 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<!-- platforms -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-all</artifactId>
<version>13.10.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.10.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hsqldb</artifactId>
<version>13.10.2-SNAPSHOT</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.10.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlanywhere</artifactId>
<version>13.10.2-SNAPSHOT</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -30,7 +30,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.4.1</version>
<version>42.4.3</version>
<optional>true</optional>
</dependency>
+9 -9
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,14 +15,14 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -46,13 +46,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -135,7 +135,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version>
<version>42.5.1</version>
<optional>true</optional>
</dependency>
@@ -143,21 +143,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
@@ -9,4 +9,5 @@ public final class CoreLog {
public static final System.Logger log = AppLog.getLogger("io.ebean.core");
public static final System.Logger internal = AppLog.getLogger("io.ebean.internal");
public static final System.Logger markedAsDeleted = AppLog.getLogger("io.ebean.MarkedAsDeleted");
}
@@ -6,10 +6,7 @@ import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Request for loading ManyToOne and OneToOne relationships.
@@ -103,7 +100,7 @@ public final class LoadBeanRequest extends LoadRequest {
/**
* Load the beans into the L2 cache if that is requested and check for load failures due to deletes.
*/
public void postLoad(List<?> list) {
public Result postLoad(List<?> list) {
Set<Object> loadedIds = new HashSet<>();
BeanDescriptor<?> desc = loadBuffer.descriptor();
// collect Ids and maybe load bean cache
@@ -114,6 +111,7 @@ public final class LoadBeanRequest extends LoadRequest {
desc.cacheBeanPutAll(list);
}
if (lazyLoadProperty != null) {
Set<Object> missedIds = new HashSet<>();
for (EntityBeanIntercept ebi : batch) {
// check if the underlying row in DB was deleted. Mark the bean as 'failed' if
// necessary but allow processing to continue until it is accessed by client code
@@ -121,8 +119,36 @@ public final class LoadBeanRequest extends LoadRequest {
if (!loadedIds.contains(id)) {
// assume this is logically deleted (hence not found)
desc.markAsDeleted(ebi.getOwner());
missedIds.add(id);
}
}
return new Result(loadedIds, missedIds);
}
return EMPTY_RESULT;
}
static final Result EMPTY_RESULT = new Result(Collections.emptySet(),Collections.emptySet());
public static class Result {
private final Set<Object> loadedIds;
private final Set<Object> missedIds;
Result(Set<Object> loadedIds, Set<Object> missedIds) {
this.loadedIds = loadedIds;
this.missedIds = missedIds;
}
public boolean markedDeleted() {
return !missedIds.isEmpty();
}
public Set<Object> missedIds() {
return missedIds;
}
public Set<Object> loadedIds() {
return loadedIds;
}
}
}
@@ -120,7 +120,7 @@ public final class LoadManyRequest extends LoadRequest {
log.log(DEBUG, "BeanCollection after lazy load was empty. type:{0} id:{1} owner:{2}", ownerBean.getClass().getName(), parentId, ownerBean);
}
} else if (loadCache && many.isUseCache()) {
desc.cacheManyPropPut(many, bc, desc.getId(bc.getOwnerBean()));
desc.cacheManyPropPut(many, bc, desc.cacheKeyForBean(bc.getOwnerBean()));
}
}
}
@@ -91,15 +91,15 @@ public final class CacheChangeSet {
/**
* Add many property remove.
*/
public <T> void addManyRemove(BeanDescriptor<T> desc, String manyProperty, Object parentId) {
many(desc, manyProperty).addRemove(parentId);
public <T> void addManyRemove(BeanDescriptor<T> desc, String manyProperty, String parentKey) {
many(desc, manyProperty).addRemove(parentKey);
}
/**
* Add many property put.
*/
public <T> void addManyPut(BeanDescriptor<T> desc, String manyProperty, Object parentId, CachedManyIds entry) {
many(desc, manyProperty).addPut(parentId, entry);
public <T> void addManyPut(BeanDescriptor<T> desc, String manyProperty, String parentKey, CachedManyIds entry) {
many(desc, manyProperty).addPut(parentKey, entry);
}
/**
@@ -164,8 +164,8 @@ public final class CacheChangeSet {
private static final class ManyChange implements CacheChange {
final ManyKey key;
final Set<Object> removes = new HashSet<>();
final Map<Object, CachedManyIds> puts = new LinkedHashMap<>();
final Set<String> removes = new HashSet<>();
final Map<String, CachedManyIds> puts = new LinkedHashMap<>();
boolean clear;
ManyChange(ManyKey key) {
@@ -183,17 +183,17 @@ public final class CacheChangeSet {
/**
* Remove entry for the given parentId.
*/
void addRemove(Object parentId) {
void addRemove(String parentKey) {
if (!clear) {
removes.add(parentId);
removes.add(parentKey);
}
}
/**
* Put entry for the given parentId.
*/
void addPut(Object parentId, CachedManyIds entry) {
puts.put(parentId, entry);
void addPut(String parentKey, CachedManyIds entry) {
puts.put(parentKey, entry);
}
@Override
@@ -201,11 +201,11 @@ public final class CacheChangeSet {
if (clear) {
key.cacheClear();
} else {
for (Map.Entry<Object, CachedManyIds> entry : puts.entrySet()) {
for (Map.Entry<String, CachedManyIds> entry : puts.entrySet()) {
key.cachePut(entry.getKey(), entry.getValue());
}
for (Object parentId : removes) {
key.cacheRemove(parentId);
for (String parentKey : removes) {
key.cacheRemove(parentKey);
}
}
}
@@ -241,12 +241,12 @@ public final class CacheChangeSet {
desc.cacheManyPropClear(manyProperty);
}
void cachePut(Object parentId, CachedManyIds entry) {
desc.cacheManyPropPut(manyProperty, parentId, entry);
void cachePut(String parentKey, CachedManyIds entry) {
desc.cacheManyPropPut(manyProperty, parentKey, entry);
}
void cacheRemove(Object parentId) {
desc.cacheManyPropRemove(manyProperty, parentId);
void cacheRemove(String parentKey) {
desc.cacheManyPropRemove(manyProperty, parentKey);
}
}
}
@@ -130,7 +130,7 @@ final class DefaultCacheHolder {
}
private ServerCacheOptions getQueryOptions(Class<?> cls) {
CacheQueryTuning tuning = AnnotationUtil.get(cls, CacheQueryTuning.class);
CacheQueryTuning tuning = AnnotationUtil.typeGet(cls, CacheQueryTuning.class);
if (tuning != null) {
return new ServerCacheOptions(tuning).applyDefaults(queryDefault);
}
@@ -138,9 +138,9 @@ final class DefaultCacheHolder {
}
private ServerCacheOptions getBeanOptions(Class<?> cls) {
Cache cache = cls.getAnnotation(Cache.class);
Cache cache = AnnotationUtil.typeGet(cls, Cache.class);
boolean nearCache = (cache != null && cache.nearCache());
CacheBeanTuning tuning = cls.getAnnotation(CacheBeanTuning.class);
CacheBeanTuning tuning = AnnotationUtil.typeGet(cls, CacheBeanTuning.class);
if (tuning != null) {
return new ServerCacheOptions(nearCache, tuning).applyDefaults(beanDefault);
}
@@ -14,10 +14,11 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.transaction.DefaultPersistenceContext;
import javax.persistence.EntityNotFoundException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.*;
/**
* Helper to handle lazy loading and refreshing of beans.
@@ -72,7 +73,8 @@ final class DefaultBeanLoader {
if (ebi.isReadOnly()) {
readOnly = Boolean.TRUE;
}
if (parentDesc.cacheManyPropLoad(many, beanCollection, parentId, readOnly)) {
final String parentKey = parentDesc.cacheKey(parentId);
if (parentDesc.cacheManyPropLoad(many, beanCollection, parentKey, readOnly)) {
return;
}
}
@@ -113,7 +115,8 @@ final class DefaultBeanLoader {
log.log(DEBUG, "BeanCollection after load was empty. Owner:{0}", beanCollection.getOwnerBean());
}
} else if (useManyIdCache) {
parentDesc.cacheManyPropPut(many, beanCollection, parentId);
final String parentKey = parentDesc.cacheKey(parentId);
parentDesc.cacheManyPropPut(many, beanCollection, parentKey);
}
}
}
@@ -135,8 +138,12 @@ final class DefaultBeanLoader {
SpiQuery<?> query = server.createQuery(loadRequest.beanType());
loadRequest.configureQuery(query, idList);
List<?> list = executeQuery(loadRequest, query);
loadRequest.postLoad(list);
final List<?> list = executeQuery(loadRequest, query);
final LoadBeanRequest.Result result = loadRequest.postLoad(list);
if (result.markedDeleted() && CoreLog.markedAsDeleted.isLoggable(DEBUG)) {
String msg = MessageFormat.format("Loaded bean marked as deleted for {0} missedIds:{1} loadedIds:{2} sql:{3} list:{4}", loadRequest.beanType(), result.missedIds(), result.loadedIds(), query.getGeneratedSql(), list);
CoreLog.markedAsDeleted.log(DEBUG, msg, new RuntimeException("LoadBeanRequest markedAsDeleted"));
}
}
/**
@@ -160,6 +160,8 @@ public final class DefaultContainer implements SpiContainer {
*/
private BootupClasses bootupClasses(DatabaseConfig config) {
BootupClasses bootup = bootupClasses1(config);
bootup.addServerConfigStartup(config.getServerConfigStartupListeners());
bootup.runServerConfigStartup(config);
bootup.addIdGenerators(config.getIdGenerators());
bootup.addPersistControllers(config.getPersistControllers());
bootup.addPostLoaders(config.getPostLoaders());
@@ -167,9 +169,7 @@ public final class DefaultContainer implements SpiContainer {
bootup.addFindControllers(config.getFindControllers());
bootup.addPersistListeners(config.getPersistListeners());
bootup.addQueryAdapters(config.getQueryAdapters());
bootup.addServerConfigStartup(config.getServerConfigStartupListeners());
bootup.addChangeLogInstances(config);
bootup.runServerConfigStartup(config);
return bootup;
}
@@ -1091,7 +1091,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> Set<T> findSet(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest request = createQueryRequest(Type.SET, query, transaction);
SpiOrmQueryRequest request = buildQueryRequest(Type.SET, query, transaction);
request.resetBeanCacheAutoMode(false);
if ((transaction == null || !transaction.isSkipCache()) && request.getFromBeanCache()) {
// hit bean cache and got all results from cache
return request.beanCacheHitsAsSet();
}
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
return (Set<T>) result;
@@ -1107,12 +1113,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <K, T> Map<K, T> findMap(Query<T> query, @Nullable Transaction transaction) {
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, transaction);
SpiOrmQueryRequest request = buildQueryRequest(Type.MAP, query, transaction);
request.resetBeanCacheAutoMode(false);
if ((transaction == null || !transaction.isSkipCache()) && request.getFromBeanCache()) {
// hit bean cache and got all results from cache
return request.beanCacheHitsAsMap();
}
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
return (Map<K, T>) result;
@@ -515,12 +515,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (query.getType() == Type.MAP) {
mergeCacheHitsToMap(result);
} else {
mergeCacheHitsToList(result);
mergeCacheHitsToCollection(result);
}
}
}
private void mergeCacheHitsToList(BeanCollection<T> result) {
private void mergeCacheHitsToCollection(BeanCollection<T> result) {
for (T hit : cacheBeans) {
result.internalAdd(hit);
}
@@ -579,6 +579,15 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return property;
}
@Override
public Set<T> beanCacheHitsAsSet() {
OrderBy<T> orderBy = query.getOrderBy();
if (orderBy != null && !orderBy.isEmpty()) {
beanDescriptor.sort(cacheBeans, orderBy.toStringFormat());
}
return new LinkedHashSet<>(cacheBeans);
}
@Override
public boolean getFromBeanCache() {
if (!query.isBeanCacheGet()) {
@@ -153,6 +153,11 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
*/
<K> Map<K,T> beanCacheHitsAsMap();
/**
* Return the bean cache hits for findMap (when all hits / no misses).
*/
Set<T> beanCacheHitsAsSet();
/**
* Reset Bean cache mode AUTO - require explicit setting for bean cache use with findList().
*/
@@ -342,8 +342,9 @@ public class BootupClasses implements Predicate<Class<?>> {
*/
@SuppressWarnings("unchecked")
private boolean isInterestingInterface(Class<?> cls) {
if (Modifier.isAbstract(cls.getModifiers())) {
// do not include abstract classes as we can
if (Modifier.isAbstract(cls.getModifiers())
|| !(Modifier.isPublic(cls.getModifiers()) || Modifier.isProtected(cls.getModifiers()))) {
// do not include abstract and non pupbic/protected classes as we can
// not instantiate them
return false;
}
@@ -38,13 +38,10 @@ public final class BeanCollectionUtil {
// returns a collection of beans
return bc.getActualEntries();
}
if (o instanceof Map<?, ?>) {
// yes, we want the entrySet (to set the keys)
return ((Map<?, ?>) o).entrySet();
} else if (o instanceof Collection<?>) {
if (o instanceof Collection<?>) {
return ((Collection<?>) o);
} else if (o instanceof Map<?, ?>) {
return ((Map<?, ?>) o).entrySet();
}
throw new PersistenceException("expecting a Map or Collection but got " + o.getClass().getName());
}
@@ -1202,26 +1202,26 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
/**
* Try to load the beanCollection from cache return true if successful.
*/
public boolean cacheManyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
return cacheHelp.manyPropLoad(many, bc, parentId, readOnly);
public boolean cacheManyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, String parentKey, Boolean readOnly) {
return cacheHelp.manyPropLoad(many, bc, parentKey, readOnly);
}
/**
* Put the beanCollection into the cache.
*/
public void cacheManyPropPut(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId) {
cacheHelp.manyPropPut(many, bc, parentId);
public void cacheManyPropPut(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, String parentKey) {
cacheHelp.manyPropPut(many, bc, parentKey);
}
/**
* Update the bean collection entry in the cache.
*/
public void cacheManyPropPut(String name, Object parentId, CachedManyIds entry) {
cacheHelp.cachePutManyIds(parentId, name, entry);
public void cacheManyPropPut(String name, String parentKey, CachedManyIds entry) {
cacheHelp.cachePutManyIds(name, parentKey, entry);
}
public void cacheManyPropRemove(String propertyName, Object parentId) {
cacheHelp.manyPropRemove(propertyName, parentId);
public void cacheManyPropRemove(String propertyName, String parentKey) {
cacheHelp.manyPropRemove(propertyName, parentKey);
}
public void cacheManyPropClear(String propertyName) {
@@ -2096,7 +2096,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
/**
* Return the cache key for the given bean (based on id value).
*/
String cacheKeyForBean(EntityBean bean) {
public String cacheKeyForBean(EntityBean bean) {
return cacheKey(idProperty.getValue(bean));
}
@@ -2112,11 +2112,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return getId((EntityBean) bean);
}
// @Override
// public Object beanId(T bean) {
// return getId((EntityBean) bean);
// }
/**
* Return the Id value for the bean with embeddedId beans converted into maps.
* <p>
@@ -226,13 +226,12 @@ final class BeanDescriptorCacheHelp<T> {
queryCache.put(id, entry);
}
void manyPropRemove(String propertyName, Object parentId) {
void manyPropRemove(String propertyName, String parentKey) {
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
if (manyLog.isLoggable(TRACE)) {
manyLog.log(TRACE, " REMOVE {0}({1}).{2}", cacheName, parentId, propertyName);
manyLog.log(TRACE, " REMOVE {0}({1}).{2}", cacheName, parentKey, propertyName);
}
collectionIdsCache.remove(parentId);
collectionIdsCache.remove(parentKey);
}
void manyPropClear(String propertyName) {
@@ -246,15 +245,15 @@ final class BeanDescriptorCacheHelp<T> {
/**
* Return the CachedManyIds for a given bean many property. Returns null if not in the cache.
*/
private CachedManyIds manyPropGet(Object parentId, String propertyName) {
private CachedManyIds manyPropGet(String propertyName, String parentKey) {
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
CachedManyIds entry = (CachedManyIds) collectionIdsCache.get(parentId);
CachedManyIds entry = (CachedManyIds) collectionIdsCache.get(parentKey);
if (entry == null) {
if (manyLog.isLoggable(TRACE)) {
manyLog.log(TRACE, " GET {0}({1}).{2} - cache miss", cacheName, parentId, propertyName);
manyLog.log(TRACE, " GET {0}({1}).{2} - cache miss", cacheName, parentKey, propertyName);
}
} else if (manyLog.isLoggable(DEBUG)) {
manyLog.log(DEBUG, " GET {0}({1}).{2} - hit", cacheName, parentId, propertyName);
manyLog.log(DEBUG, " GET {0}({1}).{2} - hit", cacheName, parentKey, propertyName);
}
return entry;
}
@@ -262,12 +261,12 @@ final class BeanDescriptorCacheHelp<T> {
/**
* Try to load the bean collection from cache return true if successful.
*/
boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, String parentKey, Boolean readOnly) {
if (many.isElementCollection()) {
// held as part of the bean cache so skip
return false;
}
CachedManyIds entry = manyPropGet(parentId, many.name());
CachedManyIds entry = manyPropGet(many.name(), parentKey);
if (entry == null) {
// not in cache so return unsuccessful
return false;
@@ -293,9 +292,9 @@ final class BeanDescriptorCacheHelp<T> {
/**
* Put the beanCollection into the cache.
*/
void manyPropPut(BeanPropertyAssocMany<?> many, Object details, Object parentId) {
void manyPropPut(BeanPropertyAssocMany<?> many, Object details, String parentKey) {
if (many.isElementCollection()) {
CachedBeanData data = (CachedBeanData) beanCache.get(parentId);
CachedBeanData data = (CachedBeanData) beanCache.get(parentKey);
if (data != null) {
try {
// add as JSON to bean cache
@@ -305,9 +304,9 @@ final class BeanDescriptorCacheHelp<T> {
CachedBeanData newData = data.update(changes, data.getVersion());
if (beanLog.isLoggable(DEBUG)) {
beanLog.log(DEBUG, " UPDATE {0}({1}) changes:{2}", cacheName, parentId, changes);
beanLog.log(DEBUG, " UPDATE {0}({1}) changes:{2}", cacheName, parentKey, changes);
}
beanCache.put(parentId, newData);
beanCache.put(parentKey, newData);
} catch (IOException e) {
log.log(ERROR, "Error updating L2 cache", e);
}
@@ -315,17 +314,17 @@ final class BeanDescriptorCacheHelp<T> {
} else {
CachedManyIds entry = createManyIds(many, details);
if (entry != null) {
cachePutManyIds(parentId, many.name(), entry);
cachePutManyIds(many.name(), parentKey, entry);
}
}
}
void cachePutManyIds(Object parentId, String manyName, CachedManyIds entry) {
void cachePutManyIds(String manyName, String parentKey, CachedManyIds entry) {
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, manyName);
if (manyLog.isLoggable(DEBUG)) {
manyLog.log(DEBUG, " PUT {0}({1}).{2} - ids:{3}", cacheName, parentId, manyName, entry);
manyLog.log(DEBUG, " PUT {0}({1}).{2} - ids:{3}", cacheName, parentKey, manyName, entry);
}
collectionIdsCache.put(parentId, entry);
collectionIdsCache.put(parentKey, entry);
}
private CachedManyIds createManyIds(BeanPropertyAssocMany<?> many, Object details) {
@@ -828,7 +827,8 @@ final class BeanDescriptorCacheHelp<T> {
Object details = many.getValue(updateRequest.entityBean());
CachedManyIds entry = createManyIds(many, details);
if (entry != null) {
changeSet.addManyPut(desc, many.name(), id, entry);
final String parentKey = desc.cacheKey(id);
changeSet.addManyPut(desc, many.name(), parentKey, entry);
}
}
}
@@ -65,7 +65,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
/**
* Flag to mark this is the id property.
*/
private final boolean id;
protected final boolean id;
private final boolean importedPrimaryKey;
/**
* Flag to make this as a dummy property for unidirecitonal relationships.
@@ -197,7 +197,8 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
if (assocBean != null) {
Object parentId = targetDescriptor.id(assocBean);
if (parentId != null) {
changeSet.addManyRemove(targetDescriptor, relationshipProperty.name(), parentId);
final String parentKey = targetDescriptor.cacheKey(parentId);
changeSet.addManyRemove(targetDescriptor, relationshipProperty.name(), parentKey);
}
}
}
@@ -655,7 +656,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
@Override
public void setValue(EntityBean bean, Object value) {
super.setValue(bean, value);
if (embedded && value instanceof EntityBean) {
if (!id && embedded && value instanceof EntityBean) {
setEmbeddedOwner(bean, value);
}
}
@@ -663,7 +664,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
@Override
public void setValueIntercept(EntityBean bean, Object value) {
super.setValueIntercept(bean, value);
if (embedded && value instanceof EntityBean) {
if (!id && embedded && value instanceof EntityBean) {
setEmbeddedOwner(bean, value);
}
}
@@ -675,8 +676,10 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
Object emb = getValue(owner);
if (emb != null) {
EntityBean embeddedBean = (EntityBean) emb;
embeddedBean._ebean_getIntercept().setEmbeddedOwner(owner, propertyIndex);
targetDescriptor.setAllLoaded(embeddedBean);
if (!id) {
embeddedBean._ebean_getIntercept().setEmbeddedOwner(owner, propertyIndex);
}
}
}
@@ -1123,7 +1123,7 @@ public class DeployBeanProperty {
private boolean matchPlatform(Platform[] platforms, Platform match) {
for (Platform platform : platforms) {
if (platform == match) {
if (platform == match || platform == match.base()) {
return true;
}
}
@@ -465,10 +465,9 @@ final class AnnotationFields extends AnnotationParser {
if (!gen.generator().isEmpty()) {
// use a custom IdGenerator
PlatformIdGenerator idGenerator = generatedPropFactory.getIdGenerator(gen.generator());
if (idGenerator == null) {
throw new IllegalStateException("No custom IdGenerator registered with name " + gen.generator());
if (idGenerator != null) {
descriptor.setCustomIdGenerator(idGenerator);
}
descriptor.setCustomIdGenerator(idGenerator);
} else if (prop.getPropertyType().equals(UUID.class)) {
descriptor.setUuidGenerator();
}
@@ -1268,4 +1268,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
return null;
}
@Override
public ExpressionList<T> clear() {
list.clear();
return this;
}
}
@@ -1068,4 +1068,9 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
}
return null;
}
@Override
public ExpressionList<T> clear() {
return exprList.clear();
}
}
@@ -205,7 +205,8 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
EntityBean ownerBean = bc.getOwnerBean();
BeanDescriptor<?> parentDesc = context.desc.descriptor(ownerBean.getClass());
Object parentId = parentDesc.getId(ownerBean);
if (parentDesc.cacheManyPropLoad(context.property, bc, parentId, context.parent.isReadOnly())) {
final String parentKey = parentDesc.cacheKey(parentId);
if (parentDesc.cacheManyPropLoad(context.property, bc, parentKey, context.parent.isReadOnly())) {
// we loaded the bean collection from cache so remove it from the buffer
for (int i = 0; i < list.size(); i++) {
// find it using instance equality - avoiding equals() and potential deadlock issue
@@ -861,7 +861,7 @@ public final class DefaultPersister implements Persister {
SpiTransaction t = request.transaction();
EntityBean orphanForRemoval = request.importedOrphanForRemoval();
if (orphanForRemoval != null) {
delete(orphanForRemoval, request.transaction(), true);
delete(orphanForRemoval, request.transaction(), false);
}
// exported ones with cascade save
@@ -1079,7 +1079,7 @@ public final class DefaultPersister implements Persister {
private void deleteOrphan(PersistRequestBean<?> request, BeanPropertyAssocOne<?> prop) {
Object origValue = request.getOrigValue(prop);
if (origValue instanceof EntityBean) {
delete((EntityBean) origValue, request.transaction(), true);
delete((EntityBean) origValue, request.transaction(), false);
}
}
@@ -35,8 +35,9 @@ final class SaveManyBeans extends SaveManyBase {
private final boolean untouchedBeanCollection;
private final Collection<?> collection;
private final boolean hasOrderColumn;
private final boolean forcedUpdate;
private int sortOrder;
private boolean insertAllChildren;
private boolean forceOrphanRemoval;
SaveManyBeans(DefaultPersister persister, boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
super(persister, insertedParent, many, parentBean, request);
@@ -49,6 +50,7 @@ final class SaveManyBeans extends SaveManyBase {
this.untouchedBeanCollection = untouchedBeanCollection();
this.collection = cascade ? BeanCollectionUtil.getActualEntries(value) : null;
this.hasOrderColumn = many.hasOrderColumn();
this.forcedUpdate = request.isForcedUpdate();
}
/**
@@ -127,10 +129,8 @@ final class SaveManyBeans extends SaveManyBase {
targetDescriptor.preAllocateIds(collection.size());
}
if (forcedUpdateOrphanRemoval()) {
// collect the Id's (to exclude from deleteManyDetails)
List<Object> detailIds = collectIds(collection, targetDescriptor, isMap);
// deleting missing children - children not in our collected detailIds
persister.deleteManyDetails(transaction, many.descriptor(), parentBean, many, detailIds, deleteMode);
// deleting orphans, anything not in our detailsIds
persister.deleteManyDetails(transaction, many.descriptor(), parentBean, many, detailIds(), deleteMode);
}
transaction.depth(+1);
saveAllBeans(orderColumn);
@@ -141,7 +141,7 @@ final class SaveManyBeans extends SaveManyBase {
}
private boolean forcedUpdateOrphanRemoval() {
return !insertedParent && many.isOrphanRemoval() && request.isForcedUpdate();
return !insertedParent && many.isOrphanRemoval() && (forceOrphanRemoval || forcedUpdate);
}
private void saveAllBeans(final BeanProperty orderColumn) {
@@ -177,10 +177,6 @@ final class SaveManyBeans extends SaveManyBase {
skipSavingThisBean = false;
// set the parent bean to detailBean
many.setJoinValuesToChild(parentBean, detail, mapKeyValue);
} else if (insertAllChildren) {
ebi.setNew();
skipSavingThisBean = false;
many.setJoinValuesToChild(parentBean, detail, mapKeyValue);
} else {
skipSavingThisBean = saveRecurseSkippable;
}
@@ -215,12 +211,10 @@ final class SaveManyBeans extends SaveManyBase {
}
/**
* Collect the Id values of the details to remove 'missing children' for stateless updates.
* Return the Id values of beans we know are being updated (any others are orphans)
*/
private List<Object> collectIds(Collection<?> collection, BeanDescriptor<?> targetDescriptor, boolean isMap) {
List<Object> detailIds = new ArrayList<>();
// stateless update with deleteMissingChildren so first
// collect the Id values to remove the 'missing children'
private List<Object> detailIds() {
final var detailIds = new ArrayList<>();
for (Object detailBean : collection) {
if (isMap) {
detailBean = ((Map.Entry<?, ?>) detailBean).getValue();
@@ -228,8 +222,10 @@ final class SaveManyBeans extends SaveManyBase {
if (detailBean instanceof EntityBean) {
Object id = targetDescriptor.id(detailBean);
if (!isNullOrZero(id)) {
// remember the Id (other details not in the collection) will be removed
detailIds.add(id);
if (forcedUpdate || !((EntityBean) detailBean)._ebean_getIntercept().isNew()) {
// Id of bean that will be updated, exclude it from orphan removal
detailIds.add(id);
}
}
}
}
@@ -261,8 +257,7 @@ final class SaveManyBeans extends SaveManyBase {
}
private void saveAssocManyIntersection(boolean queue) {
boolean forcedUpdate = request.isForcedUpdate();
boolean vanillaCollection = !(value instanceof BeanCollection<?>);
final boolean vanillaCollection = !(value instanceof BeanCollection<?>);
if (vanillaCollection || forcedUpdate) {
// delete all intersection rows and then treat all
// beans in the collection as additions
@@ -321,7 +316,7 @@ final class SaveManyBeans extends SaveManyBase {
CoreLog.log.log(System.Logger.Level.WARNING, m);
} else {
if (!many.hasImportedId(otherBean)) {
throw new PersistenceException("ManyToMany bean " + otherBean + " does not have an Id value.");
throw new PersistenceException("ManyToMany bean does not have an Id value? " + otherBean);
} else {
// build a intersection row for 'insert'
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherBean, publish);
@@ -344,10 +339,7 @@ final class SaveManyBeans extends SaveManyBase {
return;
}
if (!(value instanceof BeanCollection<?>)) {
if (!forcedUpdateOrphanRemoval() && (!insertedParent && cascade && isChangedProperty())) {
persister.addToFlushQueue(many.deleteByParentId(request.beanId(), null), transaction, 0);
insertAllChildren = true;
}
forceOrphanRemoval = !insertedParent && isChangedProperty();
} else {
BeanCollection<?> c = (BeanCollection<?>) value;
Set<?> modifyRemovals = c.getModifyRemovals();
@@ -359,7 +351,9 @@ final class SaveManyBeans extends SaveManyBase {
if (!hasOrderColumn) {
c.modifyReset();
}
if (modifyRemovals != null && !modifyRemovals.isEmpty()) {
if (modifyRemovals == null || modifyRemovals.isEmpty()) {
forceOrphanRemoval = !insertedParent && isChangedProperty();
} else {
for (Object removedBean : modifyRemovals) {
if (removedBean instanceof EntityBean) {
EntityBean eb = (EntityBean) removedBean;
@@ -585,16 +585,11 @@ final class CQueryBuilder {
}
if (distinct && dbOrderBy != null) {
// add the orderBy columns to the select clause (due to distinct)
final OrderBy<?> orderBy = query.getOrderBy();
if (orderBy != null && orderBy.supportsSelect()) {
String trimmed = DbOrderByTrim.trim(dbOrderBy);
if (query.isSingleAttribute() && select.selectSql().startsWith(trimmed)) {
// NOP, already in SQL
// TODO: what to do if we select("id").orderBy("prop,id")?
// Can we live with a query like "select t0.id, t0.prop, t0.id from"
// or should we elliminate the second "t0.id" from select
} else {
sb.append(", ").append(trimmed);
String[] tokens = DbOrderByTrim.trim(dbOrderBy).split(",");
for (String token : tokens) {
token = token.trim();
if (!DbOrderByTrim.contains(select.selectSql(), token)) {
sb.append(", ").append(token);
}
}
}
@@ -643,7 +638,7 @@ final class CQueryBuilder {
private void appendHistoryAsOfPredicate() {
if (query.isAsOfBaseTable()) {
query.incrementAsOfTableCount();
if (!historySupport.isStandardsBased()){
if (!historySupport.isStandardsBased()) {
appendAndOrWhere();
sb.append(historySupport.asOfPredicate(request.baseTableAlias()));
}
@@ -4,7 +4,7 @@ import java.util.regex.Pattern;
final class DbOrderByTrim {
private static final Pattern orderByTrim = Pattern.compile("(?i) asc\\b| desc\\b|\\b nulls first\\b|\\b nulls last\\b");
private static final Pattern orderByTrim = Pattern.compile("(?i) asc\\b| desc\\b| nulls first\\b| nulls last\\b");
/**
* Convert the dbOrderBy clause to be safe for adding to select or distinct on.
@@ -14,4 +14,21 @@ final class DbOrderByTrim {
return orderByTrim.matcher(dbOrderBy).replaceAll("");
}
/**
* Checks, if <code>sql</code> contains the <code>column</code>.
* <p>
* SQL is normally comma separated: "t0.id, t1.id, t2.name"
*/
static boolean contains(String sql, String column) {
if (sql.endsWith(column)) { // simplest way. sql ends with the column
return true;
} else if (sql.contains(column)) {
// We need to check, if it is really the correct column,
// sql="t0.name_short, t0.name_long" will match on column="t0.name"
return sql.contains(column + ",");
} else {
return false;
}
}
}
@@ -172,7 +172,7 @@ public final class SqlTreeBuilder {
String[] split = idCols.split(",");
for (String col : split) {
col = col.trim();
if (!dbOrderBy.contains(col)) {
if (!DbOrderByTrim.contains(dbOrderBy, col)) {
sb.append(", ").append(col);
}
}
@@ -5,6 +5,7 @@ import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
@@ -14,6 +15,8 @@ import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException;
import java.util.Map;
import static java.lang.System.Logger.Level.DEBUG;
/**
* Normal bean included in the query.
*/
@@ -211,6 +214,9 @@ class SqlTreeLoadBean implements SqlTreeLoad {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).valueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
if (CoreLog.markedAsDeleted.isLoggable(DEBUG)) {
CoreLog.markedAsDeleted.log(DEBUG, contextBean + " contextBean markedAsDeleted", new RuntimeException(contextBean + " contextBean markedAsDeleted"));
}
}
}
}
@@ -99,6 +99,14 @@ public class DefaultExpressionListTest extends BaseExpressionTest {
.isSameByBind(spi(exp().eq("a", 10).eq("b", 20)))).isFalse();
}
@Test
public void isSameWithClear() {
DefaultExpressionList<?> exp1 = spi(exp().eq("a", 10).eq("b", 20).clear().eq("c", 30));
DefaultExpressionList<?> exp2 = spi(exp().eq("c", 30));
same(exp1, exp2);
assertThat(exp1.isSameByBind(exp2)).isTrue();
}
@SuppressWarnings("unchecked")
@Test
void copy() {
@@ -64,4 +64,11 @@ public class DbOrderByTrimTest {
assertEquals("foo", DbOrderByTrim.trim("foo desc nulls last"));
}
@Test
void trim_nulls_withAggFunction() {
assertEquals("min(customer)", DbOrderByTrim.trim("min(customer) asc nulls last"));
assertEquals("foo,min(customer)", DbOrderByTrim.trim("foo,min(customer) asc nulls last"));
assertEquals("bar,min(customer)", DbOrderByTrim.trim("bar desc,min(customer) asc nulls last"));
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>ebean-csv-reader</artifactId>
@@ -14,21 +14,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
@@ -58,7 +58,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
@@ -1,5 +1,6 @@
package io.ebeaninternal.dbmigration.model;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
import io.ebeaninternal.dbmigration.migration.*;
import java.util.ArrayList;
@@ -125,6 +126,21 @@ public class ModelDiff {
// search for tables that are no longer used
for (MTable existingTable : baseModel.getTables().values()) {
if (!newTables.containsKey(existingTable.getName())) {
// Compounded foreign keys used in many-to-many mapping tables
existingTable.getCompoundKeys().forEach(it -> addAlterForeignKey(it.dropForeignKey(existingTable.getName())));
// Foreign keys through direct mapping (oneToMany)
existingTable.allColumns().stream()
.filter(it -> it.getForeignKeyIndex() != null)
.map(it -> {
AlterForeignKey fk = new AlterForeignKey();
fk.setName(it.getForeignKeyName());
fk.setIndexName(it.getForeignKeyIndex());
fk.setColumnNames(DdlHelp.DROP_FOREIGN_KEY);
fk.setTableName(existingTable.getName());
return fk;
})
.forEach(applyChanges::add);
addDropTable(existingTable);
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean external mapping api</name>
+6 -6
View File
@@ -4,12 +4,12 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.10.2</tag>
<tag>ebean-parent-13.11.4</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -21,7 +21,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -54,21 +54,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>ebean-jackson-jsonnode</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
+3 -3
View File
@@ -6,7 +6,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2-SNAPSHOT</version>
<version>13.11.4-SNAPSHOT</version>
</parent>
<artifactId>ebean-kotlin</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2-SNAPSHOT</version>
<version>13.11.4-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -50,7 +50,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2-SNAPSHOT</version>
<version>13.11.4-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean postgis</name>
@@ -22,14 +22,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
@@ -50,7 +50,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version>
<version>42.5.1</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
@@ -63,21 +63,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
@@ -3,6 +3,8 @@ package org.example.domain;
import io.ebean.annotation.DbArray;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -16,7 +18,11 @@ import java.util.Map;
public class Contact extends BaseModel {
@DbArray
List<String> phoneNumbers = new ArrayList<>();
List<@Size(max=20) String> phoneNumbers = new ArrayList<>();
@ElementCollection
@Size(max=10)
List<@Size(max=20) String> paths;
@Column(length = 50)
String firstName;
@@ -36,7 +42,7 @@ public class Contact extends BaseModel {
Customer customer;
@OneToMany(mappedBy = "contact")
List<ContactNote> notes;
List<@NotNull ContactNote> notes;
@OneToMany(cascade = CascadeType.PERSIST)
@MapKey(name = "key")
@@ -857,10 +857,20 @@ public class QCustomerTest {
cust.setName("testFetchByScalarValue");
cust.setPhoneNumber(new PhoneNumber("+18005555555"));
cust.save();
assertThat(new QCustomer()
var customer = new QCustomer()
.name.eq("testFetchByScalarValue")
.phoneNumber.eq(new PhoneNumber("+18005555555"))
.findOne()).isNotNull();
.findOne();
assertThat(customer).isNotNull();
var customers = new QCustomer()
.name.eq("testFetchByScalarValue")
.phoneNumber.eq(new PhoneNumber("+18005555555"))
.findList();
assertThat(customers).hasSize(1);
}
@@ -6,8 +6,8 @@ datasource.default=h2
datasource.h2.username=sa
datasource.h2.password=
datasource.h2.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY
datasource.h2.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY,VALUE
datasource.pg.username=sa
datasource.pg.password=
datasource.pg.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY
datasource.pg.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY,VALUE
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
@@ -0,0 +1,39 @@
package org.domain;
import io.ebean.Model;
import io.ebean.annotation.Cache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Cache
@Entity
public class UChild extends Model {
@Id
long id;
String name;
@ManyToOne
final UParent parent;
public UChild(UParent parent, String name) {
this.parent = parent;
this.name = name;
}
public long id() {
return id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,51 @@
package org.domain;
import io.ebean.Model;
import io.ebean.annotation.Cache;
import io.ebean.annotation.CacheBeanTuning;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Cache(enableQueryCache = true)
@CacheBeanTuning(maxSecsToLive = 1)
@Entity
public class UParent extends Model {
@Id
private UUID id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private final List<UChild> children = new ArrayList<>();
public UParent(String name) {
this.name = name;
}
public UUID id() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<UChild> children() {
return children;
}
}
@@ -5,6 +5,8 @@ import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheStatistics;
import org.domain.Person;
import org.domain.RCust;
import org.domain.UChild;
import org.domain.UParent;
import org.domain.query.QPerson;
import org.domain.query.QRCust;
import org.junit.jupiter.api.Test;
@@ -19,6 +21,32 @@ import static org.assertj.core.api.Assertions.assertThat;
class IntegrationTest {
@Test
void uuid_getPut() {
UParent b0 = new UParent("b0");
b0.children().add(new UChild(b0,"b0c0"));
b0.children().add(new UChild(b0,"b0c1"));
b0.save();
ServerCache beanCache = DB.cacheManager().beanCache(UParent.class);
beanCache.clear();
beanCache.statistics(true);
UParent found0 = DB.find(UParent.class, b0.id());
assertThat(found0.name()).isEqualTo("b0");
List<UChild> children = found0.children();
assertThat(children).hasSize(2);
UParent found1 = DB.find(UParent.class, b0.id());
assertThat(found1.name()).isEqualTo("b0");
DB.delete(found1);
ServerCacheStatistics stats1 = beanCache.statistics(true);
assertThat(stats1.getHitCount()).isEqualTo(1);
}
@Test
void mget_when_emptyCollectionOfIds() {
@@ -2,6 +2,7 @@ ebean:
dumpMetricsOnShutdown: true
dumpMetricsOptions: sql,hash,loc
test:
registerTestTenantProvider: false
redis: latest
# shutdown: stop # stop | remove
platform: h2 # h2, postgres, mysql, oracle, sqlserver, sqlite
+9 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.10.2</version>
<version>13.11.4</version>
</parent>
<name>ebean test</name>
@@ -28,20 +28,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
</dependency>
<dependency>
@@ -105,28 +105,28 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.10.2</version>
<version>13.11.4</version>
<scope>test</scope>
</dependency>
@@ -183,7 +183,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.0</version>
<version>42.5.1</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
@@ -25,7 +25,7 @@ class YugabyteSetup implements PlatformSetup {
if (!config.isUseDocker()) {
return new Properties();
}
config.setDockerVersion("2.11.2.0-b89");
config.setDockerVersion("2.16.0.1-b7");
config.setExtensions("pgcrypto");
return config.getDockerProperties();
}
@@ -38,8 +38,10 @@ public class ProviderAutoConfig {
CurrentTenantProvider tenantProvider = config.getCurrentTenantProvider();
if (tenantProvider == null) {
providerSetFlag += 2;
config.setCurrentTenantProvider(new WhoTenantProvider());
if (Boolean.parseBoolean(properties.getProperty("ebean.test.registerTestTenantProvider", "true"))) {
providerSetFlag += 2;
config.setCurrentTenantProvider(new WhoTenantProvider());
}
}
EncryptKeyManager keyManager = config.getEncryptKeyManager();
@@ -236,7 +236,95 @@ public class DtoQuery2Test extends BaseTestCase {
assertThat(stats).hasSize(2);
log.info("stats " + stats);
}
@Test
void dto_mapping_columnsWithUnderscores() {
ResetBasicData.reset();
List<DCustCamelCols0> list = server().findDto(DCustCamelCols0.class,
"select id as num_with, name as name_for_me from o_customer")
.findList();
assertThat(list).isNotEmpty();
for (DCustCamelCols0 dto : list) {
assertThat(dto.getNumWith()).isGreaterThan(0);
assertThat(dto.getNameForMe()).isNotNull();
}
}
@Test
void dto_mapping_columnsWithNoUnderscores() {
ResetBasicData.reset();
List<DCustCamelCols0> list = server().findDto(DCustCamelCols0.class,
"select id as numwith, name as nameforme from o_customer")
.findList();
assertThat(list).isNotEmpty();
for (DCustCamelCols0 dto : list) {
assertThat(dto.getNumWith()).isGreaterThan(0);
assertThat(dto.getNameForMe()).isNotNull();
}
// mapping is case-insensitive
List<DCustCamelCols0> list2 = server().findDto(DCustCamelCols0.class,
"select id as numWith, name as nameForMe from o_customer")
.findList();
assertThat(list2).isNotEmpty();
for (DCustCamelCols0 dto : list2) {
assertThat(dto.getNumWith()).isGreaterThan(0);
assertThat(dto.getNameForMe()).isNotNull();
}
}
@Test
void dto_mapping_propertyNamesCaseInsensitive() {
ResetBasicData.reset();
List<DCustCamelCols2> list = server().findDto(DCustCamelCols2.class,
"select id as numwith, name as nameforme from o_customer")
.findList();
assertThat(list).isNotEmpty();
for (DCustCamelCols2 dto : list) {
assertThat(dto.getNumWITH()).isGreaterThan(0);
assertThat(dto.getNameFORMe()).isNotNull();
}
// mapping is case-insensitive
List<DCustCamelCols2> list2 = server().findDto(DCustCamelCols2.class,
"select id as numWith, name as nameForMe from o_customer")
.findList();
assertThat(list2).isNotEmpty();
for (DCustCamelCols2 dto : list2) {
assertThat(dto.getNumWITH()).isGreaterThan(0);
assertThat(dto.getNameFORMe()).isNotNull();
}
}
@Test
void dto_mapping_columnsUsingNestedSql() {
ResetBasicData.reset();
String sql
= "select num_with, name_for_me from ( "
// we don't CARE what the nested SQL is in that the jdbc metaData
// for the column names/labels comes from the top most select
+ " select id as num_with, name as name_for_me from o_customer "
+ ") a";
List<DCustCamelCols0> list = server().findDto(DCustCamelCols0.class,
sql)
.findList();
assertThat(list).isNotEmpty();
for (DCustCamelCols0 dto : list) {
assertThat(dto.getNumWith()).isGreaterThan(0);
assertThat(dto.getNameForMe()).isNotNull();
}
}
@Test
@@ -478,4 +566,52 @@ public class DtoQuery2Test extends BaseTestCase {
this.name = name;
}
}
public static class DCustCamelCols0 {
Integer numWith;
String nameForMe;
public Integer getNumWith() {
return numWith;
}
public DCustCamelCols0 setNumWith(Integer numWith) {
this.numWith = numWith;
return this;
}
public String getNameForMe() {
return nameForMe;
}
public DCustCamelCols0 setNameForMe(String nameForMe) {
this.nameForMe = nameForMe;
return this;
}
}
public static class DCustCamelCols2 {
Integer numWITH;
String nameFORMe;
public Integer getNumWITH() {
return numWITH;
}
public DCustCamelCols2 setNumWITH(Integer numWITH) {
this.numWITH = numWITH;
return this;
}
public String getNameFORMe() {
return nameFORMe;
}
public DCustCamelCols2 setNameFORMe(String nameFORMe) {
this.nameFORMe = nameFORMe;
return this;
}
}
}
@@ -15,7 +15,6 @@ import org.tests.model.basic.ECustomId;
import org.tests.model.controller.FindControllerMain;
import org.tests.model.controller.SoftRefA;
import org.tests.model.controller.SoftRefB;
import org.tests.model.controller.TestBeanFindController;
import java.util.List;
@@ -1,16 +1,17 @@
package org.tests.model.controller;
package io.ebean.xtest.event;
import io.ebean.bean.BeanCollection;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanQueryRequest;
import io.ebean.plugin.BeanType;
import org.tests.model.controller.FindControllerMain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestBeanFindController implements BeanFindController {
class TestBeanFindController implements BeanFindController {
@Override
public boolean isRegisterFor(final Class<?> cls) {
@@ -0,0 +1,48 @@
package misc.migration.v1_0;
import javax.persistence.*;
import java.util.List;
/**
* Test-model referencing two other tables, which gets dropped for migration test in order to check for correct table drop
* procedure (first drop foreign keys, then the tables).
*
* @author Jonas P&ouml;hler, FOCONIS AG
*/
@Entity
@Table(name = "drop_main")
public class DropMain {
@Id
Integer id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
List<DropRefOne> refsOne;
@ManyToMany(cascade = CascadeType.ALL)
List<DropRefMany> refsMany;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<DropRefOne> getRefsOne() {
return refsOne;
}
public void setRefsOne(List<DropRefOne> refsOne) {
this.refsOne = refsOne;
}
public List<DropRefMany> getRefsMany() {
return refsMany;
}
public void setRefsMany(List<DropRefMany> refsMany) {
this.refsMany = refsMany;
}
}
@@ -0,0 +1,35 @@
package misc.migration.v1_0;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import java.util.List;
@Entity
@Table(name = "drop_ref_many")
public class DropRefMany {
@Id
Integer id;
@ManyToMany(cascade = {}, mappedBy = "refsMany")
List<DropMain> parents;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<DropMain> getParents() {
return parents;
}
public void setParents(List<DropMain> parents) {
this.parents = parents;
}
}
@@ -0,0 +1,33 @@
package misc.migration.v1_0;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "drop_ref_one")
public class DropRefOne {
@Id
Integer id;
@ManyToOne(cascade = {})
DropMain parent;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public DropMain getParent() {
return parent;
}
public void setParent(DropMain parent) {
this.parent = parent;
}
}
@@ -1,8 +1,10 @@
package org.tests.basic;
import io.ebean.annotation.Platform;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
@@ -22,6 +24,7 @@ public class TestLimitQuery extends BaseTestCase {
rob();
}
@IgnorePlatform({Platform.MYSQL, Platform.MARIADB})
@Test
public void testMaxRowsZeroWithFirstRow() {
@@ -40,7 +43,7 @@ public class TestLimitQuery extends BaseTestCase {
String sql = query.getGeneratedSql();
if (isH2()) {
assertThat(sql).contains("offset 3");
assertThat(sql).contains("limit 0");
assertThat(sql).doesNotContain("limit");
}
}
@@ -1,8 +1,11 @@
package org.tests.basic;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.DatabaseFactory;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
import io.ebean.config.DatabaseConfig;
import io.ebean.xtest.BaseTestCase;
import io.ebeaninternal.api.SpiPersistenceContext;
import io.ebeaninternal.api.SpiTransaction;
import org.junit.jupiter.api.Disabled;
@@ -12,15 +15,17 @@ import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.validation.constraints.Size;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class TestPersistenceContext extends BaseTestCase {
public class TestPersistenceContext extends BaseTestCase {
@Test
void testReload() {
@@ -191,29 +196,135 @@ class TestPersistenceContext extends BaseTestCase {
}
}
@Disabled // run manually
@Test
void testPcScopes_with_findEachFindList() {
for (int i = 0; i < 5000; i++) {
Customer c = new Customer();
c.setName("Customer #" + i);
DB.save(c);
Order o = new Order();
o.setCustomer(c);
DB.save(o);
@Embeddable
public static class TmId {
private final UUID id1;
private final UUID id2;
public TmId(UUID id1, UUID id2) {
this.id1 = id1;
this.id2 = id2;
}
for (int i = 0; i < 1000; i++) {
try (Transaction txn = DB.beginTransaction()) {
List<Customer> customers = new ArrayList<>();
DB.find(Customer.class).select("id").findEach(customers::add);
SpiPersistenceContext pc = ((SpiTransaction) txn).getPersistenceContext();
assertThat(pc.toString()).contains("Customer=size:5000 (5000 weak)");
customers.clear();
customers = DB.find(Customer.class).select("id").findList();
public UUID getId1() {
return id1;
}
assertThat(pc.toString()).contains("Customer=size:5000"); // We expect ALWAYS 5000 entries in the PC
}
public UUID getId2() {
return id2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TmId tmId = (TmId) o;
return Objects.equals(id1, tmId.id1) && Objects.equals(id2, tmId.id2);
}
@Override
public int hashCode() {
return Objects.hash(id1, id2);
}
}
@Entity
// @Cache(enableQueryCache = true, enableBeanCache = false)
public static class TestModel2 {
@EmbeddedId
private TmId id;
@Size(max = 255)
private String someData;
public String getSomeData() {
return someData;
}
public void setSomeData(String someData) {
this.someData = someData;
}
public TmId getId() {
return id;
}
public void setId(TmId id) {
this.id = id;
}
}
@Test
@Disabled
void initDb() {
DatabaseConfig config = new DatabaseConfig();
config.setName("h2-batch");
config.loadFromProperties();
config.setDdlExtra(false);
config.getDataSourceConfig().setUsername("sa");
config.getDataSourceConfig().setPassword("sa");
config.getDataSourceConfig().setUrl("jdbc:h2:file:./testsFile3;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE");
config.addClass(TestModel2.class);
config.addClass(TmId.class);
DatabaseFactory.create(config);
String base = "x".repeat(240);
// 10 mio TestModel - each needs about 1/4 kbytes -> 2,5 GB in total
List<TestModel2> batch = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
TestModel2 m = new TestModel2();
TmId id = new TmId(UUID.randomUUID(), UUID.randomUUID());
m.setId(id);
m.setSomeData(base + i); // ensure we have not duplicates
batch.add(m);
if (i % 1000 == 0) {
DB.saveAll(batch);
batch.clear();
}
if (i % 100000 == 0) {
System.out.println(i);
}
}
DB.saveAll(batch);
}
@Test
@Disabled
void testFindEachFindList() {
DatabaseConfig config = new DatabaseConfig();
config.setName("h2-batch");
config.loadFromProperties();
config.setDdlRun(false);
config.getDataSourceConfig().setUsername("sa");
config.getDataSourceConfig().setPassword("sa");
config.getDataSourceConfig().setUrl("jdbc:h2:file:./testsFile3;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE");
config.addClass(TestModel2.class);
config.addClass(TmId.class);
DatabaseFactory.create(config);
AtomicInteger i = new AtomicInteger();
System.out.println("Doing findEach");
DB.find(TestModel2.class).select("*").findEach(c -> {
i.incrementAndGet();
});
System.out.println("Read " + i + " entries");
i.set(0);
System.out.println("Doing findStream");
DB.find(TestModel2.class).select("*").findStream().forEach(c -> i.incrementAndGet());
System.out.println("Read " + i + " entries");
i.set(0);
System.out.println("Doing findIterate");
QueryIterator<TestModel2> iter = DB.find(TestModel2.class).select("*").findIterate();
while (iter.hasNext()) {
iter.next();
i.incrementAndGet();
}
System.out.println("Read " + i + " entries");
System.out.println("Doing FindList, will hold all entries in memory. Expect OOM with -Xmx100m.");
List<TestModel2> lst = DB.find(TestModel2.class).select("*").findList();
System.out.println("Read " + lst.size() + " entries");
}
}
@@ -5,6 +5,7 @@ import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.ForPlatform;
import io.ebean.annotation.Platform;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.EBasic;
@@ -19,7 +20,6 @@ import static org.junit.jupiter.api.Assertions.*;
public class TestQueryForUpdate extends BaseTestCase {
@Test
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testForUpdate() {
ResetBasicData.reset();
@@ -35,13 +35,35 @@ public class TestQueryForUpdate extends BaseTestCase {
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("with (updlock)");
} else {
} else if (!isDb2()){
assertThat(sqlOf(query)).contains("for update");
}
}
@Test
@ForPlatform({ Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testForUpdate_withLimit() {
ResetBasicData.reset();
Query<Customer> query;
try (final Transaction transaction = DB.beginTransaction()) {
query = DB.find(Customer.class)
.forUpdate()
.setMaxRows(3)
.order().desc("id");
query.findList();
}
if (isSqlServer()) {
assertThat(sqlOf(query)).contains("with (updlock)");
} else if (!isOracle() && !isDb2()) {
// Oracle does not support FOR UPDATE with FETCH
assertThat(sqlOf(query)).contains("for update");
}
}
@Test
@ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testForUpdate_when_alreadyInPCAsReference() {
ResetBasicData.reset();
Order o0 = DB.find(Order.class).orderBy("id").setMaxRows(1).findOne();
@@ -75,7 +97,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})
public void testForUpdate_when_alreadyInPCAsReference_usingLock() {
ResetBasicData.reset();
Order o0 = DB.find(Order.class).orderBy("id").setMaxRows(1).findOne();
@@ -110,7 +132,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})
public void testForUpdate_when_alreadyInPC() {
EBasic basic = new EBasic("test PC cache");
@@ -124,7 +146,7 @@ public class TestQueryForUpdate extends BaseTestCase {
assertThat(basic0).isNotNull();
EBasic basic1 = DB.find(EBasic.class)
.setId( basic.getId())
.setId(basic.getId())
.forUpdate()
.findOne();
+120 -3
View File
@@ -1,11 +1,12 @@
package org.tests.cache;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheStatistics;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,6 +16,7 @@ import org.tests.model.basic.OCachedBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,10 +56,51 @@ public class TestBeanCache extends BaseTestCase {
assertThat(sql).isEmpty();
}
@Test
public void idsInFindMap() {
List<OCachedBean> beans = createBeans(Arrays.asList("m0", "m1", "m2", "m3", "m4", "m5", "m6"));
List<Long> ids = beans.stream().map(OCachedBean::getId).collect(Collectors.toList());
beanCache.clear();
beanCache.statistics(true);
Query<OCachedBean> query = DB.find(OCachedBean.class).setUseCache(true);
// Test findIds
LoggedSql.start();
query.copy()
.where().idIn(ids.subList(0, 1))
.findMap(); // cache key is: 3/d[{/c1000}]/w[List[IdIn[?1],]]
if (isPostgresCompatible()) {
assertThat(LoggedSql.stop().get(0)).contains("t0.id = any(?)");
} else {
assertThat(LoggedSql.stop().get(0)).contains("in (?)");
}
LoggedSql.start();
query.copy()
.where().idIn(ids.subList(0, 4))
.findMap(); // cache key is: 3/d[{/c1000}]/w[List[IdIn[?5],]]
if (isPostgresCompatible()) {
assertThat(LoggedSql.stop().get(0)).contains("t0.id = any(?)");
} else {
assertThat(LoggedSql.stop().get(0)).contains("in (?,?,?,?,?)");
}
LoggedSql.start();
query.copy()
.where().idIn(ids.subList(2, 6))
.findMap(); // same cache key as above and same SQL above
if (isPostgresCompatible()) {
assertThat(LoggedSql.stop().get(0)).contains("t0.id = any(?)");
} else {
assertThat(LoggedSql.stop().get(0)).contains("in (?,?,?,?,?)");
}
}
@Test
public void idsIn_explicitCache_expect_cachePut() {
List<OCachedBean> beans = createBeans(Arrays.asList("k0","k1"));
List<OCachedBean> beans = createBeans(Arrays.asList("k0", "k1"));
List<Long> ids = beans.stream().map(OCachedBean::getId).collect(Collectors.toList());
beanCache.clear();
@@ -157,6 +200,80 @@ public class TestBeanCache extends BaseTestCase {
}
}
@Test
public void testFindSet() {
List<OCachedBean> beans = createBeans(Arrays.asList("z0", "z1", "z2"));
List<Long> ids = beans.stream().map(OCachedBean::getId).collect(Collectors.toList());
beanCache.clear();
beanCache.statistics(true);
LoggedSql.start();
log.info("All misses (0 of 3) ...");
Set<OCachedBean> set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertThat(set).hasSize(3);
assertBeanCacheHitMiss(0, 3);
List<String> sql = LoggedSql.collect();
assertThat(sql).hasSize(1);
if (isH2()) {
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?,?,?,?,?)");
}
log.info("All hits (3 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(3, 0);
assertThat(set).hasSize(3);
sql = LoggedSql.collect();
assertThat(sql).hasSize(0); // no misses
// remove a bean so that we get a "partial" hit (2 out of 3 in cache)
beanCache.remove(beans.get(0).getId().toString());
log.info("Partial hits (2 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(2, 1);
assertThat(set).hasSize(3);
sql = LoggedSql.collect();
assertThat(sql).hasSize(1);
if (isH2()) {
// fetch the miss from DB
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?)");
}
// remove beans so that we get a "partial" hit (1 out of 3 in cache)
beanCache.remove(beans.get(1).getId().toString());
beanCache.remove(beans.get(2).getId().toString());
log.info("Partial hits (1 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(1, 2);
assertThat(set).hasSize(3);
sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
if (isH2()) {
// fetch the misses from DB
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?,?,?,?,?)");
}
}
private void assertBeanCacheHitMiss(int hitCount, int missCount) {
ServerCacheStatistics statistics = beanCache.statistics(true);
assertThat(statistics.getHitCount()).isEqualTo(hitCount);
@@ -183,7 +300,7 @@ public class TestBeanCache extends BaseTestCase {
Country country = DB.find(Country.class)
.where()
.eq("name","NotValid")
.eq("name", "NotValid")
.findOne();
assertThat(country).isNull();
@@ -14,13 +14,12 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class TestCacheCollectionIds extends BaseTestCase {
class TestCacheCollectionIds extends BaseTestCase {
private ServerCacheManager cacheManager = DB.cacheManager();
private final ServerCacheManager cacheManager = DB.cacheManager();
@Test
public void test() {
void test() {
ResetBasicData.reset();
awaitL2Cache();
@@ -75,7 +74,6 @@ public class TestCacheCollectionIds extends BaseTestCase {
}
private int fetchCustomer(Integer id) {
Customer customer2 = DB.find(Customer.class, id);
List<Contact> contacts2 = customer2.getContacts();
@@ -91,7 +89,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
* When updating a ManyToMany relations also the collection cache must be updated.
*/
@Test
public void testUpdatingCollectionCacheForManyToManyRelations() {
void testUpdatingCollectionCacheForManyToManyRelations() {
// arrange
ResetBasicData.reset();
@@ -107,7 +105,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
dummyToLoad.getCountries().size();
ServerCache cachedBeanCountriesCache = cacheManager.collectionIdsCache(OCachedBean.class, "countries");
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(cachedBean.getId());
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(cachedBean.getId()));
// confirm the starting data and cache entry
assertEquals(2, dummyToLoad.getCountries().size());
@@ -124,7 +122,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
// Get the data to assert/check against
OCachedBean result = DB.find(OCachedBean.class, cachedBean.getId());
cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(result.getId());
cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(result.getId()));
// assert that data and cache both show correct data
assertEquals(1, result.getCountries().size());
@@ -134,7 +132,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
}
@Test
public void testChangingCollectionByEditingConnectedCachedBean() {
void testChangingCollectionByEditingConnectedCachedBean() {
ResetBasicData.reset();
OCachedBean cachedBean = new OCachedBean();
@@ -174,7 +172,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
}
@Test
public void testChangingCollectionByEditingConnectedNotCachedBean() {
void testChangingCollectionByEditingConnectedNotCachedBean() {
ResetBasicData.reset();
OCachedBean cachedBean = new OCachedBean();
@@ -213,13 +211,12 @@ public class TestCacheCollectionIds extends BaseTestCase {
DB.delete(cachedBean);
}
/**
* When updating a ManyToMany relations also the collection cache must be updated.
* Alternate to above test where in this case the bean is dirty - loadedBean.setName("goodbye");.
*/
@Test
public void testUpdatingCollectionCacheForManyToManyRelationsWithUpdatedBean() {
void testUpdatingCollectionCacheForManyToManyRelationsWithUpdatedBean() {
// arrange
ResetBasicData.reset();
@@ -235,7 +232,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
dummyToLoad.getCountries().size();
ServerCache cachedBeanCountriesCache = cacheManager.collectionIdsCache(OCachedBean.class, "countries");
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(cachedBean.getId());
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(cachedBean.getId()));
// confirm the starting data and cache entry
assertEquals(2, dummyToLoad.getCountries().size());
@@ -253,7 +250,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
// Get the data to assert/check against
OCachedBean result = DB.find(OCachedBean.class, cachedBean.getId());
cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(result.getId());
cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(result.getId()));
// assert that data and cache both show correct data
assertEquals(1, result.getCountries().size());
@@ -266,7 +263,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
* When updating a ManyToMany relations also the collection cache must be updated.
*/
@Test
public void testUpdatingCollectionCacheForManyToManyRelationsWithinStatelessUpdate() {
void testUpdatingCollectionCacheForManyToManyRelationsWithinStatelessUpdate() {
// arrange
ResetBasicData.reset();
@@ -289,7 +286,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
// assert that the cache contains the expected entry
assertEquals(1, cachedBeanCountriesCache.size());
CachedManyIds dummyEntry = (CachedManyIds) cachedBeanCountriesCache.get(dummyLoad.getId());
CachedManyIds dummyEntry = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(dummyLoad.getId()));
assertNotNull(dummyEntry);
assertEquals(2, dummyEntry.getIdList().size());
assertTrue(dummyEntry.getIdList().contains("NZ"));
@@ -307,7 +304,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
assertEquals(1, cachedBeanCountriesCache.size());
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(update.getId());
CachedManyIds cachedManyIds = (CachedManyIds) cachedBeanCountriesCache.get(String.valueOf(update.getId()));
// assert cache updated
assertEquals(1, cachedManyIds.getIdList().size());
@@ -321,8 +318,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
}
@Test
public void testUpdating_noChange() throws InterruptedException {
void testUpdating_noChange() throws InterruptedException {
ResetBasicData.reset();
try (Transaction txn = DB.beginTransaction()) {
@@ -355,7 +351,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
*/
@Test
@Disabled
public void testClearingCollectionCacheOnORMUpdate() {
void testClearingCollectionCacheOnORMUpdate() {
// arrange
ResetBasicData.reset();
@@ -390,7 +386,7 @@ public class TestCacheCollectionIds extends BaseTestCase {
*/
@Test
@Disabled
public void testClearingCollectionCacheOnExternalModification() {
void testClearingCollectionCacheOnExternalModification() {
// arrange
ResetBasicData.reset();
@@ -162,16 +162,18 @@ public class TestQueryCache extends BaseTestCase {
sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
LoggedSql.start();
findCountNoTxn();
sql = LoggedSql.stop();
assertThat(sql).hasSize(0);
LoggedSql.start();
findCountTxn();
sql = LoggedSql.stop();
assertThat(sql).hasSize(0);
// Oracle does not support READ_UNCOMMITTED as expected
if (!isOracle()) {
LoggedSql.start();
findCountTxn();
sql = LoggedSql.stop();
assertThat(sql).hasSize(0);
}
}
private void findCountNoTxn() {
@@ -1,6 +1,7 @@
package org.tests.cascade;
import io.ebean.DB;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
@@ -9,6 +10,7 @@ import java.util.List;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestOrphanCollectionReplacement extends BaseTestCase {
@@ -41,7 +43,16 @@ class TestOrphanCollectionReplacement extends BaseTestCase {
updatedRoles.addAll(List.of(role));
fetchedParent.setChildren(updatedRoles);
LoggedSql.start();
DB.save(fetchedParent);
var sql = LoggedSql.stop();
if (isH2() || isPostgresCompatible()) { // using deleted=true vs deleted=1
assertThat(sql).hasSize(4);
assertThat(sql.get(0)).contains("update coone_many set deleted=true where coone_id = ? and not ( id ");
assertThat(sql.get(1)).contains(" -- bind(");
assertThat(sql.get(2)).contains("insert into coone_many (coone_id, name, deleted) values (?,?,?)");
assertThat(sql.get(3)).contains(" -- bind(");
}
}
COOne fetchedUser2 = DB.find(COOne.class, parentId);
@@ -189,7 +189,7 @@ public class TestChangeLog extends BaseTestCase {
return DatabaseFactory.create(config);
}
public static class TDChangeLogPrepare implements ChangeLogPrepare {
static class TDChangeLogPrepare implements ChangeLogPrepare {
@Override
public boolean prepare(ChangeSet changes) {
changes.setUserId("appUser1");
@@ -198,7 +198,7 @@ public class TestChangeLog extends BaseTestCase {
}
}
public static class TDChangeLogListener implements ChangeLogListener {
static class TDChangeLogListener implements ChangeLogListener {
ObjectMapper objectMapper = new ObjectMapper();
@@ -226,7 +226,7 @@ public class TestChangeLog extends BaseTestCase {
}
public static class TDChangeLogRegister implements ChangeLogRegister {
static class TDChangeLogRegister implements ChangeLogRegister {
@Override
public ChangeLogFilter getChangeFilter(Class<?> beanType) {
@@ -0,0 +1,18 @@
package org.tests.idkeys;
import io.ebean.DB;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.idkeys.db.EaObject;
import static org.assertj.core.api.Assertions.assertThat;
class TestEaObject extends BaseTestCase {
@Test
void insert() {
EaObject bean = new EaObject("fred");
DB.save(bean);
assertThat(bean.id()).isGreaterThan(0);
}
}
@@ -0,0 +1,36 @@
package org.tests.idkeys.db;
import io.ebean.Model;
import javax.persistence.*;
@Entity
@Table(name = "ea_object")
public class EaObject extends Model {
@Id
@Column(name = "object_id", nullable = false)
@GeneratedValue(
strategy = GenerationType.AUTO,
generator = "t_object_sequence_generator"
)
@SequenceGenerator(
name = "t_object_sequence_generator",
sequenceName = "object_id_seq"
)
long id;
final String name;
public EaObject(String name) {
this.name = name;
}
public long id() {
return id;
}
public String name() {
return name;
}
}
@@ -0,0 +1,59 @@
package org.tests.model.basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import java.util.List;
@Entity
@Table(name = "e_basic_tree")
public class EBasicTree {
@Id
private int id;
@ManyToOne
private EBasicTree parent;
@OneToMany
@OrderBy("ref.name")
private List<EBasicTree> children;
@ManyToOne
private EBasic ref;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public EBasicTree getParent() {
return parent;
}
public void setParent(EBasicTree parent) {
this.parent = parent;
}
public List<EBasicTree> getChildren() {
return children;
}
public void setChildren(List<EBasicTree> children) {
this.children = children;
}
public EBasic getRef() {
return ref;
}
public void setRef(EBasic ref) {
this.ref = ref;
}
}
@@ -29,7 +29,7 @@ public class MyEBasicConfigStartup implements ServerConfigStartup {
serverConfig.add(new EbasicBulkListener());
}
public static class EbasicBulkListener implements BulkTableEventListener {
private static class EbasicBulkListener implements BulkTableEventListener {
final Set<String> s = new HashSet<>();
@@ -49,7 +49,7 @@ public class MyEBasicConfigStartup implements ServerConfigStartup {
}
public static class EbasicPersistList extends AbstractBeanPersistListener {
private static class EbasicPersistList extends AbstractBeanPersistListener {
@Override
public boolean isRegisterFor(Class<?> cls) {
@@ -0,0 +1,43 @@
package org.tests.o2m;
import io.ebean.DB;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.o2m.dm.GoodsEntity;
import org.tests.o2m.dm.WorkflowEntity;
import org.tests.o2m.dm.WorkflowOperationEntity;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class StatefulO2MSoftDelete extends BaseTestCase {
@Test
void statefulUpdateShouldntDelete() {
var bomGoods = new GoodsEntity();
DB.save(bomGoods);
var goods = new GoodsEntity();
var workflow = new WorkflowEntity();
var operation1 = new WorkflowOperationEntity();
operation1.setName("operation 1");
goods.setWorkflowEntity(workflow);
workflow.setOperations(List.of(operation1));
DB.save(goods);
LoggedSql.start();
// replace workflow entity
var goodsFromDB = DB.find(GoodsEntity.class, goods.getId());
goodsFromDB.setWorkflowEntity(new WorkflowEntity());
DB.update(goodsFromDB);
var updateSql = LoggedSql.stop();
updateSql.forEach(sql -> assertThat(sql).doesNotContain("delete from workflow_entity"));
if (isH2()) {
assertThat(updateSql.get(4)).contains("update workflow_operation_entity set deleted=true where workflow_id = ?");
assertThat(updateSql.get(6)).contains("update workflow_entity set when_modified=?, deleted=? where id=?");
}
}
}
@@ -5,10 +5,7 @@ import io.ebean.DB;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.o2m.dm.GoodsEntity;
import org.tests.o2m.dm.PersonEntity;
import org.tests.o2m.dm.WorkflowEntity;
import org.tests.o2m.dm.WorkflowOperationEntity;
import org.tests.o2m.dm.*;
import java.io.StringWriter;
import java.util.List;
@@ -140,7 +137,14 @@ class TestOneToManyStatelessUpdateResultsInSoftDelete extends BaseTestCase {
assertThat(goodsAfterInsert.getWorkflowEntity().getOperations()).hasSize(1);
goodsAfterInsert.getWorkflowEntity().setOperations(List.of());
LoggedSql.start();
DB.save(goodsAfterInsert);
var sql = LoggedSql.collect();
if (isH2() || isPostgresCompatible()) { // using deleted=true vs deleted=1
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("update workflow_operation_entity set deleted=true where workflow_id = ?");
}
assertThat(goodsAfterInsert.getWorkflowEntity().getOperations()).isEmpty();
assertThat(DB.find(GoodsEntity.class, goods.getId()).getWorkflowEntity().getOperations()).isEmpty();
@@ -157,12 +161,27 @@ class TestOneToManyStatelessUpdateResultsInSoftDelete extends BaseTestCase {
// Using save() throws io.ebean.DuplicateKeyException: Error when batch flush on sql: insert into workflow_entity ...
// Must be an update() and not save() for this to be a "stateless update"
LoggedSql.collect();
DB.update(goodsStateless);
sql = LoggedSql.collect();
assertThat(sql).isNotEmpty();
if (isH2() || isPostgresCompatible()) { // using deleted=true vs deleted=1
assertThat(sql).hasSize(7);
assertThat(sql.get(0)).contains("update workflow_entity set when_modified=? where id=?");
assertThat(sql.get(1)).contains(" -- bind(");
assertThat(sql.get(2)).contains("update workflow_operation_entity set deleted=true where workflow_id = ?");
assertThat(sql.get(3)).contains(" -- bind(");
assertThat(sql.get(4)).contains("insert into workflow_operation_entity (name, version, when_created, when_modified");
assertThat(sql.get(5)).contains(" -- bind(");
assertThat(sql.get(6)).contains("update goods_entity set when_modified=?, workflow_entity_id=? where id=?");
}
var ops = workflow.getOperations();
// shouldn't contain deleted operations
assertThat(ops).hasSize(1);
assertThat(goodsStateless.getWorkflowEntity().getOperations().get(0).getId()).isNotEqualTo(operation1.getId());
LoggedSql.stop();
}
@Test
@@ -197,17 +216,23 @@ class TestOneToManyStatelessUpdateResultsInSoftDelete extends BaseTestCase {
// uncommenting this lines makes the test pass
//assertThat(goodsStateless.getWorkflowEntity().getOperations().size()).isEqualTo(0);
var sql = LoggedSql.stop();
sql.forEach(System.out::println);
System.out.println("BEFORE TRY");
LoggedSql.start();
var sql = LoggedSql.collect();
if (isH2() || isPostgresCompatible()) { // using deleted=true vs deleted=1
assertThat(sql).hasSize(5);
assertThat(sql.get(0)).contains("update workflow_entity set when_modified=? where id=?");
assertThat(sql.get(1)).contains(" -- bind(");
assertThat(sql.get(2)).contains("update workflow_operation_entity set deleted=true where workflow_id = ?");
assertThat(sql.get(3)).contains(" -- bind(");
assertThat(sql.get(4)).contains("update goods_entity set when_modified=?, workflow_entity_id=? where id=?");
}
try (var writer = new StringWriter()) {
var mapper = new ObjectMapper();
mapper.writeValue(writer, goodsStateless);
sql = LoggedSql.stop();
sql.forEach(System.out::println);
// queries fired to load the object graph for writing as json
assertThat(sql).hasSize(7);
sql.forEach(s -> assertThat(s).startsWith("select "));
/*
select t0.id, t0.name, t0.workflow_entity_id, t0.version, t0.when_created, t0.when_modified from goods_entity t0 where t0.id = ?; --bind(4, ) --micros(161)
select t0.id, t0.name, t0.version, t0.when_created, t0.when_modified, t0.created_by, t0.updated_by, t0.workflow_entity_id from goods_entity t0 where t0.id = ?; --bind(4, ) --micros(525)
@@ -230,9 +255,89 @@ class TestOneToManyStatelessUpdateResultsInSoftDelete extends BaseTestCase {
writer.flush();
var serialized = writer.toString();
System.out.println(serialized);
// System.out.println(serialized);
assertThat(serialized).isNotEmpty();
var readGoods = mapper.readValue(writer.toString(), GoodsEntity.class);
assertThat(readGoods.getWorkflowEntity().getOperations()).hasSize(0);
}
}
@Test
void setArrayListDoInsertInsteadUpdate() {
var attachment1 = new Attachment();
attachment1.setName("File1");
var attachment2 = new Attachment();
attachment2.setName("File2");
var goods = new GoodsEntity();
goods.setName("goods1");
goods.setAttachments(List.of(attachment1, attachment2));
DB.save(goods);
String goodAsJson = DB.json().toJson(goods);
var marshaledGoods = DB.json().toBean(GoodsEntity.class, goodAsJson);
var attachment3a = new Attachment();
attachment3a.setName("File3");
marshaledGoods.getAttachments().add(attachment3a);
var persistedGoods = DB.find(GoodsEntity.class, goods.getId());
// this was not deleting orphans and so the inserts throw exception due primary key conflict
persistedGoods.setAttachments(marshaledGoods.getAttachments());
LoggedSql.start();
try {
logger.info("Saving goods with set new attachments list");
DB.save(persistedGoods);
} catch (Exception e) {
logger.error("Insert instead update", e);
}
var sql = LoggedSql.collect();
assertThat(sql).isNotEmpty();
assertThat(sql.get(0)).contains("delete from attachment where goods_entity_id = ?");
assertThat(sql.get(1)).contains(" -- bind(");
assertThat(sql.get(2)).contains("insert into attachment (id, goods_entity_id, name, ");
assertThat(sql.get(3)).contains(" -- bind(");
assertThat(sql.get(4)).contains(" -- bind(");
if (isH2() || isPostgresCompatible() || isMySql()) { // i.e. using identity, not using sequence
assertThat(sql.get(5)).contains("insert into attachment (goods_entity_id, name,");
assertThat(sql.get(6)).contains(" -- bind(");
}
persistedGoods = DB.find(GoodsEntity.class, goods.getId());
// this works good using .clear() and .addAll()
// because here we are mutating the collection, it detects the
// orphan removals occurring via the .clear()
marshaledGoods = DB.json().toBean(GoodsEntity.class, goodAsJson);
var attachment3b = new Attachment();
attachment3b.setName("File3");
marshaledGoods.getAttachments().add(attachment3b);
persistedGoods.getAttachments().clear();
persistedGoods.getAttachments().addAll(marshaledGoods.getAttachments());
LoggedSql.collect();
try {
logger.info("Saving goods with clear/added attachments");
DB.save(persistedGoods);
} catch (Exception e) {
logger.error("Insert instead update", e);
}
sql = LoggedSql.stop();
assertThat(sql.get(0)).contains("delete from attachment where id=?");
assertThat(sql.get(1)).contains(" -- bind(");
assertThat(sql.get(2)).contains(" -- bind(");
assertThat(sql.get(3)).contains(" -- bind(");
assertThat(sql.get(4)).contains("insert into attachment (id, goods_entity_id, name,");
assertThat(sql.get(5)).contains(" -- bind(");
assertThat(sql.get(6)).contains(" -- bind(");
if (isH2() || isPostgresCompatible()) { // using identity, not using sequence
assertThat(sql).hasSize(9);
assertThat(sql.get(7)).contains("insert into attachment (goods_entity_id, name, ");
assertThat(sql.get(8)).contains(" -- bind(");
}
var persistedGoods2 = DB.find(GoodsEntity.class, goods.getId());
assertThat(persistedGoods2.getAttachments()).hasSize(3);
}
}
@@ -0,0 +1,16 @@
package org.tests.o2m.dm;
import javax.persistence.Entity;
@Entity
public class Attachment extends HistoryColumns {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -1,8 +1,7 @@
package org.tests.o2m.dm;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import javax.persistence.*;
import java.util.List;
@Entity
public class GoodsEntity extends HistoryColumns {
@@ -11,6 +10,9 @@ public class GoodsEntity extends HistoryColumns {
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
private WorkflowEntity workflowEntity;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<Attachment> attachments;
public String getName() {
return name;
}
@@ -26,4 +28,12 @@ public class GoodsEntity extends HistoryColumns {
public void setWorkflowEntity(WorkflowEntity workflowEntity) {
this.workflowEntity = workflowEntity;
}
public List<Attachment> getAttachments() {
return attachments;
}
public void setAttachments(List<Attachment> attachments) {
this.attachments = attachments;
}
}
@@ -1,9 +1,11 @@
package org.tests.query;
import io.ebean.annotation.Platform;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import io.ebean.PagedList;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
@@ -17,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class TestAddOrderByWithFirstRowsMaxRows extends BaseTestCase {
@IgnorePlatform({Platform.MYSQL, Platform.MARIADB})
@Test
public void test_firstRows() {

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