Compare commits

...
Author SHA1 Message Date
Rob Bygrave effcb86174 [maven-release-plugin] prepare release ebean-parent-13.6.6 2022-08-02 08:56:41 +12:00
Rob Bygrave 7e50e6e427 Bump ebean-agent to 13.6.6 (no functional change) 2022-08-02 08:49:09 +12:00
Rob Bygrave 47b940f672 #2760 - Add ServerMetrics.asData() ... for consistency 2022-08-02 08:35:48 +12:00
Rob Bygrave 01d5aa8199 #2760 - Add ServerMetrics.asJson() ... to support conversion of collected metrics to json 2022-08-01 16:54:49 +12:00
Rob Bygrave 7474430a63 #2768 - ENH: Add eqIfPresent() - a helper expression for fluid style when some EQ are optional 2022-08-01 16:36:09 +12:00
Rob Bygrave f930471beb Update README to put build status badges at top 2022-08-01 10:19:32 +12:00
Rob Bygrave 3a84e4183d Fix platform specific asserts with TestQuerySingleAttribute using limit/offset 2022-08-01 09:45:33 +12:00
Rob Bygrave d12dc9bfed Fix platform specific asserts with TestQuerySingleAttribute using limit/offset 2022-08-01 09:37:34 +12:00
Rob Bygrave 5f689dee1b No effective change - tidy test only, TestQuerySingleAttribute 2022-08-01 09:20:38 +12:00
Rob Bygrave 08d3a3b2f5 Fix platform specific assert in test TestQuerySingleAttribute 2022-08-01 09:16:55 +12:00
Rob Bygrave 4ed5f91963 #2756 - Fix for Bug findSingleAttributeList o2m maxrows
Allow maxRows use in this case
2022-07-29 22:37:06 +12:00
Rob Bygrave f36e4543ee #2755 - Effectively fixed by #2753, format only change 2022-07-29 18:08:31 +12:00
Rob Bygrave 37f92bf967 Merge branch 'bug-singleattributelist-o2m-orderby' of github.com:FOCONIS/ebean into FOCONIS-bug-singleattributelist-o2m-orderby 2022-07-29 18:07:22 +12:00
Rob Bygrave eb14531b66 #2754 - Adjust test query for oneToMany_notNull() 2022-07-29 17:29:56 +12:00
Rob Bygrave 6c1a3647f9 Merge branch 'bug-findsingleattributelist-o2m-notnull' of github.com:FOCONIS/ebean into FOCONIS-bug-findsingleattributelist-o2m-notnull 2022-07-29 17:29:10 +12:00
Rob Bygrave fa9e9be003 #2753 - Fix for, Bug findSingleAttributeList o2m distinct 2022-07-29 17:12:51 +12:00
Rob Bygrave 02ead0bcdb Merge branch 'bug-findsingleattributelist-o2m-distinct' of github.com:FOCONIS/ebean into FOCONIS-bug-findsingleattributelist-o2m-distinct 2022-07-29 16:58:04 +12:00
Rob Bygrave 892e7bc84a Update test migration output due to remove of - NOTE: table has @History #2764
-- NOTE: table has @History - special migration may be necessary
2022-07-29 16:47:42 +12:00
Rob Bygrave 4bdcd49eab Javadoc tidy for Database and DB 2022-07-29 16:46:18 +12:00
Rob Bygrave 7a0de51721 Javadoc tidy for Database and DB 2022-07-29 16:39:13 +12:00
Rob BygraveandGitHub 0ea44b36dc Merge pull request #2764 from FOCONIS/fix-history-warning
Fix: DDL will get wrong hint for special migration
2022-07-29 08:40:24 +12:00
Rob BygraveandGitHub 35e1aa2737 Merge pull request #2763 from FOCONIS/fix-tojson-with-target
Fix: toJson must use setIntercept if target bean is passed
2022-07-29 08:38:42 +12:00
Roland Praml dab428ead5 Fix: DDL will get wrong hint for special migration 2022-07-28 15:10:37 +02:00
Roland Praml dbcc779731 Fix: toJson must use setIntercept if target bean is passed 2022-07-28 15:07:05 +02:00
Rob Bygrave 3c2b5f253f Tidy DLoadContext only 2022-07-27 22:28:15 +12:00
Rob Bygrave 31c20ca9a2 Format and imports on test code only 2022-07-27 22:26:26 +12:00
Rob Bygrave 0100d024d9 #2750 #2751 SoftDeleted entity included via lazy loading (Jackson serialisation)
The effective fix is in DLoadContext, only allow includeSoftDeletes to be set from
the query when the query is SpiQuery.Mode.NORMAL (not a lazy loading query).
2022-07-27 22:25:10 +12:00
Rob Bygrave 7a6d91c2f4 Merge branch 'update_ignores_soft_delete' of github.com:Ichtil/ebean into Ichtil-update_ignores_soft_delete 2022-07-27 21:22:16 +12:00
Rob Bygrave 31ac0f794f Add avaje-applog-slf4j dependency to ebean-api
This means by default AppLog logging goes to slf4j-api. Exclude this dependency to otherwise
control the AppLog System.Logger implementation.
2022-07-27 21:12:19 +12:00
Rob Bygrave 648bdf4553 Bump ebean-dll-runner to 2.2 2022-07-27 15:07:17 +12:00
Rob Bygrave bda0786924 #2760 - Add MetaInfoManager.metricsAsJson() ... to support conversion of collected metrics to json 2022-07-27 09:31:58 +12:00
Rob Bygrave 64311b2b9d Merge branch 'master' of github.com:ebean-orm/ebean 2022-07-26 21:25:54 +12:00
Rob Bygrave 743acf1f30 Bump avaje-config to 2.2 and ebean-datasource 8.2, these use AppLog.getLogger() to obtain System.Logger 2022-07-26 21:25:38 +12:00
Rob BygraveandGitHub 74fef50b67 Merge pull request #2758 from evolvedhat/master
Update README.md
2022-07-25 13:33:48 +12:00
evolvedhatandGitHub 185404a537 Merge pull request #1 from evolvedhat/evolvedhat-patch-1
Update README.md
2022-07-24 15:58:47 -07:00
Rob BygraveandGitHub ced5bb1089 Merge pull request #2757 from tobias-/patch-2
Add notIn(Query) to query beans
2022-07-21 08:18:24 +12:00
SnōwballandGitHub 52759e0510 Add notIn(Query) to query beans
Missing from query beans, but is available in the `ExpressionList` class.
2022-07-20 14:54:30 +02:00
Alexander Wagner 7db2210ba4 Bug findsingleattributelist o2m maxrows 2022-07-20 13:47:17 +02:00
Alexander Wagner 9b80dd97c9 Bug findsingleattributelist o2m orderby 2022-07-20 13:38:38 +02:00
Alexander Wagner 23ca0e716c Bug findsingleattributelist o2m notNull 2022-07-20 09:16:10 +02:00
Alexander Wagner eac03a0721 assert 2022-07-20 09:02:06 +02:00
Alexander Wagner cf8f099447 test for findSingleAttributeList o2m distinct 2022-07-20 09:02:06 +02:00
Rob Bygrave 6698dda8ae Improve Javadoc only for InterceptReadOnly and InterceptReadWrite 2022-07-20 10:45:27 +12:00
Rob Bygrave 1cb011df5b Improve Javadoc only for EntityBeanIntercept and InterceptReadOnly 2022-07-20 10:38:02 +12:00
Rob Bygrave ac1e1757e8 #2748 - Fix partially loaded bean scenario with .setDisableLazyLoading(true) .setBeanCacheMode(CacheMode.PUT) // force query to hit database 2022-07-20 08:16:43 +12:00
Rob Bygrave 48404fc85d #2748 - Fix setDisableLazyLoading(true) ... does not set fully loaded state [fully loaded bean scenario] 2022-07-20 07:55:42 +12:00
Rob Bygrave 9252e72581 #2748 - Fix such that .setLoadBeanCache(false) ... sets CacheMode.OFF 2022-07-20 07:45:20 +12:00
Jan Klička 64f99f5205 2750 failing test case 2022-07-15 17:49:10 +02:00
Rob Bygrave a5e3b9e68a #2749 - Bump ebean-datasource, ebean-annotation, ebean-types, persistence-api 2022-07-15 21:53:32 +12:00
evolvedhatandGitHub 4b43751512 Update README.md
Added descriptions from the website to give a better idea of what the project does.
2022-07-13 11:39:59 -07:00
Rob Bygrave 5f6efd29ef #2743 - Postgres DDL - For create table, improve column ordering for tighter storage 2022-07-07 22:06:21 +12:00
Rob Bygrave 110bc614e4 #2743 - Postgres DDL - For create table, improve column ordering for tighter storage 2022-07-07 13:45:06 +12:00
Rob Bygrave ec89d31a32 Bump to 13.6.5-SNAPSHOT after release 2022-07-07 12:11:54 +12:00
Rob Bygrave fbae9cad8a #2742 - ModelContainer.applyChangeSet(ModelContainer.java:167) - IllegalArgumentException: No rule for io.ebeaninternal.dbmigration.migration.CreateSchema 2022-07-07 12:03:39 +12:00
Rob Bygrave fdfe2533c9 [maven-release-plugin] prepare for next development iteration 2022-07-06 20:59:11 +12:00
Rob Bygrave 7e3d39ac1a [maven-release-plugin] prepare release ebean-parent-13.6.5 2022-07-06 20:59:04 +12:00
Rob Bygrave ce19837649 Bump avaje-lang to 1.1 with the only change being the removal of maven pom descriptors from META-INF/maven 2022-07-06 20:49:49 +12:00
Rob Bygrave 11e20edb59 #2741 - Bump avaje-config to 2.1 and modify ebean-test to support use of ${docker.host} in test container jdbc urls 2022-07-06 20:47:54 +12:00
Rob Bygrave 88b6a60feb #2730 - Secondary @OneToMany fetch query is not happening if the same Entity type is fetched 2022-07-06 20:19:41 +12:00
Rob Bygrave 43dac07d5b #2740 - Bump ebean-test-containers to 6.2 2022-07-06 14:41:24 +12:00
Rob Bygrave 04434215d0 #2740 - Bump ebean-test-containers to 6.2 2022-07-06 14:27:28 +12:00
Rob Bygrave 52e6c0c625 #2736 - findDto nonsupport setter chain (accessor style setters, both fluid style and non fluid style) 2022-07-05 10:37:55 +12:00
Rob Bygrave 745fbe883e #2737 - Mapping of TimeZone doesn't have enough characters 2022-07-05 09:05:13 +12:00
Rob Bygrave 283e0b66fa #2734 - maven build - excluding maven descriptor (pom and properties) from built artifacts 2022-07-04 17:53:28 +12:00
Rob Bygrave 523deb20f4 #2732 - ebean-agent - skip transactional profiling aware enhancement on query beans 2022-07-04 17:05:25 +12:00
Rob Bygrave 23d52ca192 #2731 - Change ebean-querybean annotations from Retention RUNTIME to CLASS 2022-07-04 16:58:06 +12:00
Rob Bygrave d20d276d56 #2728 - Fix for stateless update with orphanRemoval=true and softDelete 2022-07-04 12:22:27 +12:00
Rob Bygrave 5b92ac6e02 Merge branch 'deleted_one_to_many_children_bug' of https://github.com/Ichtil/ebean into Ichtil-deleted_one_to_many_children_bug 2022-07-01 17:12:45 +12:00
Jan Klička 6392f90f32 Add more failing test cases 2022-06-29 18:41:19 +02:00
Jan Klička bb8f3831b8 Testcase demonstrating stateless update resulting in a delete 2022-06-29 16:09:51 +02:00
Rob Bygrave 4bb43814b7 Run build with -T 8 2022-06-28 10:30:30 +12:00
Rob Bygrave 95c1554642 Run build with -T 8, clean test only for main build 2022-06-28 10:24:35 +12:00
Rob Bygrave 2cd59c5166 Run build with -T 8 2022-06-28 09:59:37 +12:00
Rob Bygrave afdb1df7ce Testing nuodb 4.3.2, but it isn't supporting getGeneratedKeys for jdbc batch inserts
That breaks a lot of tests
2022-06-16 23:32:04 +12:00
Rob Bygrave fa6fdf124d Fix test BasicProfileLocationTest 2022-06-16 13:52:27 +12:00
Rob Bygrave 1e044f03ed Adjust test DefaultPersistenceContextTest 2022-06-15 22:25:46 +12:00
Rob Bygrave 7989fcd6ce Bump to 13.6.5-SNAPSHOT after release 2022-06-15 22:22:04 +12:00
Rob Bygrave a5256df6f2 [maven-release-plugin] prepare for next development iteration 2022-06-14 16:14:25 +12:00
Rob Bygrave fa11dac2b2 [maven-release-plugin] prepare release ebean-parent-13.6.4 2022-06-14 16:14:18 +12:00
Rob Bygrave c40ca2fad7 Bump agent to 13.6.4 (no effective change) 2022-06-14 16:09:13 +12:00
Rob BygraveandGitHub 5b9359f509 Merge pull request #2719 from ebean-orm/feature/postgres-default-table-partition-refactor
DDL - Refactor DDL for Postgres and YugabyteDB to just create a default partition table
2022-06-14 16:08:28 +12:00
Rob Bygrave 403556d8b2 DDL - Refactor DDL for Postgres and YugabyteDB to just create a default partition table
Removes the need and use of  PostgresPlatform.tablePartitionsExist() and PostgresPlatform.tablePartitionInit() altogether.
2022-06-14 16:00:54 +12:00
Rob Bygrave 06ad2edfc1 #2718 - [Yugabyte] Fix such that builtin table partition functions are included in DDL (when we use table partitioning) 2022-06-14 15:39:34 +12:00
Rob BygraveandGitHub 16e2489ba0 Merge pull request #2717 from ebean-orm/feature/string-jsonb
Support Postgres JSONB/JSON with String - @DbJsonb String content;
2022-06-14 15:09:05 +12:00
Rob Bygrave 162b3449e8 Put ebean.properties back to default to h2 2022-06-14 15:03:35 +12:00
Rob Bygrave 8c3ed6996e Put postgresql jdbc back to 42.3.3 2022-06-14 14:59:39 +12:00
Rob Bygrave 583c5f74eb Support Postgres JSONB/JSON with String - @DbJsonb String content; 2022-06-14 14:57:50 +12:00
Rob Bygrave ab047996d2 Add build badge for Oracle 2022-06-14 09:18:17 +12:00
Rob Bygrave 239f87bb5d Rename Oracle GH WF build 2022-06-13 22:39:35 +12:00
Rob Bygrave 5be3b7717c #2716 - Refactor ScalarType interface to make use of default methods 2022-06-13 22:38:15 +12:00
Rob Bygrave e29d83a379 #2710 - Update PersistRequestBean with checkAllMutableProperties() and checkAnyMutableProperties() 2022-06-13 18:58:38 +12:00
Rob Bygrave 8301fd5e74 #2710 - JSONB fields are not considered dirty after modified in BeanPersistController preUpdate 2022-06-13 18:35:42 +12:00
Rob Bygrave 3e3647816d #2715 - [ebean-test-containers] Fix for Postgis to support extraDb (second database), Update Oracle container 2022-06-13 15:44:52 +12:00
Rob Bygrave 9aa7ae79e2 #2713 - Improve javadoc of Finder, BeanFinder, BeanRepository - deprecate use of BeanFinder server field (migrate to database) 2022-06-09 13:26:48 +12:00
Rob Bygrave 168c940b79 #2712 - Bump jedis to 4.2.3 (from 4.2.2) 2022-06-09 12:29:52 +12:00
Rob Bygrave 1ee18a1823 #2711 - Gradle: Change querybean generator from isolating to aggregating 2022-06-09 12:26:36 +12:00
Rob BygraveandGitHub c02ab7340c Merge pull request #2708 from FOCONIS/fix-localtime
Part 1: Fix read/write/query LocalTime values
2022-06-09 12:00:06 +12:00
Rob BygraveandGitHub c67773505d Merge pull request #2706 from FOCONIS/findsingleattributeset
ENH: Add support for findSingleAttributeSet()
2022-06-09 11:50:04 +12:00
Noemi Praml 9c354919e5 refactoring
(cherry picked from commit 43e28c4f5c747cdda2e3547a8db593eab490ceec)
2022-05-31 10:49:09 +02:00
Noemi Praml c8be59fd95 it fixes the test
(cherry picked from commit d2e21aa3dcbd4ae59dd8d1ff5404d94c298f087b)
2022-05-31 10:47:32 +02:00
Noemi Praml d1a40b4739 failing test 2022-05-31 10:47:08 +02:00
Noemi Praml bb9cfe9d0f add support for findSingleAttributeSet 2022-05-24 11:09:56 +02:00
Rob Bygrave ede2ad4d54 Bump test modules to 13.6.4-SNAPSHOT after release 2022-05-24 14:01:05 +12:00
Rob Bygrave 1060503fe1 [maven-release-plugin] prepare for next development iteration 2022-05-24 13:46:16 +12:00
265 changed files with 3083 additions and 1781 deletions
+1 -1
View File
@@ -36,5 +36,5 @@ jobs:
# - name: Maven single test
# run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false
- name: Build with Maven
run: mvn clean package
run: mvn -T 8 clean test
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: db2
run: mvn clean test -Dprops.file=testconfig/ebean-db2.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-db2.properties
+1 -1
View File
@@ -37,5 +37,5 @@ jobs:
- name: Maven version
run: mvn --version
- name: H2Database
run: mvn clean package
run: mvn -T 8 clean package
+1 -1
View File
@@ -35,5 +35,5 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn package
run: mvn -T 8 test
+1 -1
View File
@@ -39,5 +39,5 @@ jobs:
- name: Maven version
run: mvn --version
- name: Build with Maven
run: mvn package
run: mvn -T 8 test
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: mariadb 10.6
run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mariadb.properties
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: mysql
run: mvn clean test -Dprops.file=testconfig/ebean-mysql.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mysql.properties
@@ -1,5 +1,5 @@
name: Oracle18
name: Oracle
on:
workflow_dispatch:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: oracle
run: mvn clean test -Dprops.file=testconfig/ebean-oracle.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-oracle.properties
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: postgres
run: mvn clean test -Dprops.file=testconfig/ebean-postgres.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-postgres.properties
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: sqlserver 2017
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
+35 -4
View File
@@ -1,26 +1,56 @@
[![Build](https://github.com/ebean-orm/ebean/actions/workflows/build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/build.yml)
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ebean-orm/ebean/blob/master/LICENSE)
[![Multi-JDK Build](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml)
[![JDK 18-ea](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml)
##### Build with database platforms
[![H2Database](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml)
[![Postgres](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml)
[![MySql](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml)
[![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml)
[![Oracle](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml)
[![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml)
[![Yugabyte](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml)
#### Builds against EA (Early Access) versions of Java (19, Loom, panama etc)
##### Build with Java Early Access versions
[![ebean EA](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml)
[![datasource EA](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml)
[![migration EA](https://github.com/ebean-orm/ebean-migration/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-migration/actions/workflows/jdk-ea.yml)
[![test-docker EA](https://github.com/ebean-orm/ebean-test-docker/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-test-docker/actions/workflows/jdk-ea.yml)
[![ebean-agent EA](https://github.com/ebean-orm/ebean-agent/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-agent/actions/workflows/jdk-ea.yml)
----------------------
# Ebean ORM for Java & Kotlin
**Multiple abstraction levels**: Ebean provides multiple levels of query abstraction [ORM Queries, mixed with SQL](https://ebean.io/docs/intro/queries/orm-query), [DTO Queries](https://ebean.io/docs/intro/queries/dto-query), [SqlQuery and JDBC](https://ebean.io/docs/intro/queries/sql-query).
Work at the highest level of abstraction and drop down levels as needed.
**Database migrations**: Built in [DB migration](https://ebean.io/docs/db-migrations/) generation and running. Support for "rebase" migrations as well as repeatable, init and 'normal' migrations.
**Awesome SQL**: Ebean produces SQL that you would hand craft yourself. Use great SQL, never generate SQL cartesian product, always honor relational limit/offset.
**Automated query tuning**: For ORM queries Ebean can profile the object graph being used and either [automatically tune the query](https://ebean.io/docs/query/background/autotune).
**Docker test containers**: [Docker test containers](https://ebean.io/docs/testing/) for all the supported databases. Get 100% test coverage on all the features of the database we use.
**Type safe queries**: We can build queries using type safe [query beans](https://ebean.io/docs/query/query-beans). IDE auto-complete when writing queries, compile time checking and it's FUN.
**Performance isn't optional**: Optimise queries to only fetch what we need (partial objects). Automatically avoid N+1 via a smart load context.
#### Benefits of ORM
* Automatically avoid N+1
* L2 caching to reduce database load
* Queries mixing database and L2 cache
* Automatically tune ORM queries
* Elasticsearch for search or L3 cache
----------------------
# Sponsors
<table>
<tbody>
@@ -50,13 +80,14 @@
</table>
## Need help?
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
Post questions or issues to the [Ebean google group](https://groups.google.com/forum/#!forum/ebean)
or [github discussions](https://github.com/ebean-orm/ebean/discussions)
## Documentation
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
## Maven central
[Maven central - io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20)
[Maven central - g:io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20)
## Building Ebean from source
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<artifactId>composites</artifactId>
+31 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean api</name>
@@ -27,7 +27,13 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>2.0</version>
<version>2.2</version>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog-slf4j</artifactId>
<version>1.0</version>
</dependency>
<!--
@@ -37,25 +43,25 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-lang</artifactId>
<version>1.0</version>
<version>1.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>2.2.5</version>
<version>3.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>8.0</version>
<version>8.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-types</artifactId>
<version>2.2</version>
<version>3.0</version>
</dependency>
<dependency>
@@ -103,4 +109,23 @@
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/ebean-maven-version.txt</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/ebean-maven-version.txt</exclude>
</excludes>
</resource>
</resources>
</build>
</project>
@@ -12,6 +12,7 @@ import java.util.Optional;
* </p>
* <pre>{@code
*
* @Component
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
@@ -26,29 +27,37 @@ import java.util.Optional;
*
* @param <I> The ID type
* @param <T> The Bean type
*
* @see BeanRepository
*/
@NonNullApi
public abstract class BeanFinder<I,T> {
/**
* Migrate to using database rather than server.
*/
@Deprecated
protected final Database server;
protected final Database database;
protected final Class<T> type;
/**
* Create with the given bean type and Database instance.
*
* @param type The bean type
* @param server The Database instance typically created via Spring factory or equivalent.
* @param database The Database instance typically created via Spring factory or equivalent.
*/
protected BeanFinder(Class<T> type, Database server) {
protected BeanFinder(Class<T> type, Database database) {
this.type = type;
this.server = server;
this.database = database;
this.server = database;
}
/**
* Return the Database to use.
*/
public Database db() {
return server;
return database;
}
/**
@@ -70,10 +79,10 @@ public abstract class BeanFinder<I,T> {
* <p>
* This is equivalent to {@link DB#byName(String)}
*
* @param server The name of the Database. If this is null then the default Database is returned.
* @param name The name of the Database. If this is null then the default Database is returned.
*/
public Database db(String server) {
return DB.byName(server);
public Database db(String name) {
return DB.byName(name);
}
/**
@@ -6,11 +6,15 @@ import io.ebean.bean.EntityBean;
import java.util.Collection;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* Provides find and persist functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* Extend the BeanRepository with additional finder and persisting methods as needed by the
* application. The intention is to keep all the related logic together, for example, all the
* persisting and finding logic for Customer would be in CustomerRepository.
*
* <pre>{@code
*
* @Repository
* @Component
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
@@ -50,10 +54,10 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* }</pre>
*
* @param type The bean type
* @param server The Database instance typically created via Spring factory or equivalent
* @param database The Database instance typically created via Spring factory or equivalent
*/
protected BeanRepository(Class<T> type, Database server) {
super(type, server);
protected BeanRepository(Class<T> type, Database database) {
super(type, database);
}
/**
@@ -122,8 +126,8 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Save all the beans in the collection.
*/
public int saveAll(Collection<T> bean) {
return db().saveAll(bean);
public int saveAll(Collection<T> beans) {
return db().saveAll(beans);
}
/**
+5 -5
View File
@@ -238,7 +238,7 @@ public final class DB {
}
/**
* The batch will be flushing automatically but you can use this to explicitly
* The batch will be flushing automatically but, you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
@@ -961,7 +961,7 @@ public final class DB {
*
* DB.execute(scope, new TxRunnable() {
* public void run() {
* User u1 = DB.find(User.class, 1);
* User u1 = DB.find(User.class, 1);
* ...
* }
* });
@@ -1010,9 +1010,9 @@ public final class DB {
*
* DB.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = DB.find(User.class, 1);
* ...
* return u1.getEmail();
* User u1 = DB.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* });
* }</pre>
+113 -212
View File
@@ -30,10 +30,8 @@ import java.util.concurrent.Callable;
* singleton (see {@link DatabaseConfig#setRegister(boolean)}). The DB
* singleton is essentially a map of Database's that have been registered
* with it.
* </p>
* <p>
* The Database can then be retrieved later via {@link DB#byName(String)}.
* </p>
*
* <h5>The 'default' Database</h5>
* <p>
@@ -41,18 +39,15 @@ import java.util.concurrent.Callable;
* (see {@link DatabaseConfig#setDefaultServer(boolean)}. Many methods on DB
* such as {@link DB#find(Class)} etc are actually just a convenient way to
* call methods on the 'default/primary' Database.
* </p>
*
* <h5>Constructing a Database</h5>
* <p>
* Database's are constructed by the DatabaseFactory. They can be created
* Databases are constructed by the DatabaseFactory. They can be created
* programmatically via {@link DatabaseFactory#create(DatabaseConfig)} or they
* can be automatically constructed on demand using configuration information in
* the application.properties file.
* </p>
*
* <h5>Example: Get a Database</h5>
* <p>
* <pre>{@code
*
* // Get access to the Human Resources Database
@@ -71,22 +66,19 @@ import java.util.concurrent.Callable;
*
* <h5>Database vs DB API</h5>
* <p>
* Database provides additional API compared with DB. For example it
* Database provides additional API compared with DB. For example, it
* provides more control over the use of Transactions that is not available in
* the DB API.
* </p>
*
* <p>
* <em>External Transactions:</em> If you wanted to use transactions created
* externally to Ebean then Database provides additional methods where you
* can explicitly pass a transaction (that can be created externally).
* </p>
*
* <p>
* <em>Bypass ThreadLocal Mechanism:</em> If you want to bypass the built in
* <em>Bypass ThreadLocal Mechanism:</em> If you want to bypass the built-in
* ThreadLocal transaction management you can use the createTransaction()
* method. Example: a single thread requires more than one transaction.
* </p>
*
* @see DB
* @see DatabaseFactory
@@ -104,12 +96,10 @@ public interface Database {
* Shutdown the Database instance programmatically.
* <p>
* This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly.
* </p>
* <p>
* If the under underlying DataSource is the Ebean implementation then you
* also have the option of shutting down the DataSource and deregistering the
* also have the option of shutting down the DataSource and de-registering the
* JDBC driver.
* </p>
*
* @param shutdownDataSource if true then shutdown the underlying DataSource if it is the Ebean
* DataSource implementation.
@@ -155,10 +145,10 @@ public interface Database {
* <p>
* Note many platforms have multiple specific platform types so often we want to
* get the base platform via {@link Platform#base()}.
* </p>
*
* <pre>{@code
*
* Platform platform = database.getPlatform().base();
* Platform platform = database.platform().base();
* if (platform == Platform.MYSQL) {
* // do MySql specific function
* }
@@ -178,7 +168,6 @@ public interface Database {
* Return the BeanState for a given entity bean.
* <p>
* This will return null if the bean is not an enhanced entity bean.
* </p>
*/
BeanState beanState(Object bean);
@@ -192,7 +181,6 @@ public interface Database {
* <p>
* For example, if the id value passed in is a String but ought to be a Long or UUID etc
* then it will automatically be converted.
* </p>
*
* @param bean The entity bean to set the id value on.
* @param id The id value to set.
@@ -204,7 +192,6 @@ public interface Database {
* <p>
* When null is passed in for b, then the 'OldValues' of a is used for the
* difference comparison.
* </p>
*/
Map<String, ValuePair> diff(Object newBean, Object oldBean);
@@ -214,7 +201,6 @@ public interface Database {
* Useful if you use BeanPostConstructListeners or &#64;PostConstruct Annotations.
* In this case you should not use "new Bean...()". Making all bean constructors protected
* could be a good idea here.
* </p>
*/
<T> T createEntityBean(Class<T> type);
@@ -248,7 +234,6 @@ public interface Database {
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
@@ -304,17 +289,14 @@ public interface Database {
* <p>
* You can use the methods on the Query object to specify fetch paths,
* predicates, order by, limits etc.
* </p>
* <p>
* You then use findList(), findSet(), findMap() and findOne() to execute
* the query and return the collection or bean.
* </p>
* <p>
* Note that a query executed by {@link Query#findList()}
* {@link Query#findSet()} etc will execute against the same Database from
* which is was created.
* </p>
* <p>
*
* <pre>{@code
*
* // Find order 2 specifying explicitly the parts of the object graph to
@@ -344,7 +326,7 @@ public interface Database {
* Create a query using native SQL.
* <p>
* The native SQL can contain named parameters or positioned parameters.
* </p>
*
* <pre>{@code
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
@@ -367,12 +349,10 @@ public interface Database {
* <p>
* This will only work when a IdGenerator is on the bean such as for beans
* that use a DB sequence or UUID.
* </p>
* <p>
* For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do
* not need to use this method generally. It is made available for more
* complex cases where it is useful to get an ID prior to some processing.
* </p>
*/
Object nextId(Class<?> beanType);
@@ -381,10 +361,8 @@ public interface Database {
* going back to the database.
* <p>
* This produces and returns a new list with the sort and filters applied.
* </p>
* <p>
* Refer to {@link Filter} for an example of its use.
* </p>
*/
<T> Filter<T> filter(Class<T> beanType);
@@ -401,12 +379,10 @@ public interface Database {
* <p>
* If you leave off any keywords the defaults are ascending order and treating
* nulls as high values.
* </p>
* <p>
* Note that the sorting uses a Comparator and Collections.sort(); and does
* not invoke a DB query.
* </p>
* <p>
*
* <pre>{@code
*
* // find orders and their customers
@@ -431,17 +407,15 @@ public interface Database {
<T> void sort(List<T> list, String sortByClause);
/**
* Create a orm update where you will supply the insert/update or delete
* Create an orm update where you will supply the insert/update or delete
* statement (rather than using a named one that is already defined using the
* &#064;NamedUpdates annotation).
* <p>
* The orm update differs from the sql update in that it you can use the bean
* name and bean property names rather than table and column names.
* </p>
* <p>
* An example:
* </p>
* <p>
*
* <pre>{@code
*
* // The bean name and properties - "topic","postCount" and "id"
@@ -466,7 +440,6 @@ public interface Database {
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with DB before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param sql The SQL query to execute.
@@ -479,7 +452,6 @@ public interface Database {
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with DB before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param namedQuery The name of the query
@@ -493,10 +465,8 @@ public interface Database {
*
* <p>
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
* </p>
* <p>
* Refer to {@link #findNative(Class, String)} for native sql queries returning entity beans.
* </p>
*/
SqlQuery sqlQuery(String sql);
@@ -505,11 +475,9 @@ public interface Database {
* <p>
* Use this to execute a Insert Update or Delete statement. The statement will
* be native to the database and contain database table and column names.
* </p>
*
* <p>
* See {@link SqlUpdate} for example usage.
* </p>
*
* @return The SqlUpdate instance to set parameters and execute
*/
@@ -522,7 +490,7 @@ public interface Database {
/**
* Register a TransactionCallback on the currently active transaction.
* <p/>
* <p>
* If there is no currently active transaction then a PersistenceException is thrown.
*
* @param transactionCallback The transaction callback to be registered with the current transaction.
@@ -536,7 +504,6 @@ public interface Database {
* You will want to do this if you want multiple Transactions in a single
* thread or generally use transactions outside of the TransactionThreadLocal
* management.
* </p>
*/
Transaction createTransaction();
@@ -544,7 +511,6 @@ public interface Database {
* Create a new transaction additionally specifying the isolation level.
* <p>
* Note that this transaction is NOT stored in a thread local.
* </p>
*/
Transaction createTransaction(TxIsolation isolation);
@@ -552,86 +518,77 @@ public interface Database {
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
* use batch mode, change the transaction isolation level, use savepoints or
* log comments to the transaction log.
* </p>
* <p>
* Example of using a transaction to span multiple calls to find(), save()
* etc.
* </p>
* <p>
* Example of using a transaction to span multiple calls to find(), save() etc.
*
* <h3>Using try with resources</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* // start a transaction (stored in a ThreadLocal)
* try (Transaction txn = database.beginTransaction()) {
*
* try (Transaction txn = database.beginTransaction()) {
* Order order = database.find(Order.class, 10);
* ...
* database.save(order);
*
* Order order = database.find(Order.class, 10);
* ...
* database.save(order);
*
* txn.commit();
* }
* txn.commit();
* }
*
* }</pre>
* <p>
*
* <h3>Using try finally block</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* Transaction txn = database.beginTransaction();
* try {
* Order order = database.find(Order.class,10);
* // start a transaction (stored in a ThreadLocal)
* Transaction txn = database.beginTransaction();
* try {
* Order order = database.find(Order.class,10);
*
* database.save(order);
*
* txn.commit();
*
* } finally {
* txn.end();
* }
* database.save(order);
* txn.commit();
*
* } finally {
* txn.end();
* }
* }</pre>
* <p>
*
* <h3>Transaction options</h3>
* <pre>{@code
*
* try (Transaction txn = database.beginTransaction()) {
* try (Transaction txn = database.beginTransaction()) {
*
* // explicitly turn on/off JDBC batch use
* txn.setBatchMode(true);
* txn.setBatchSize(50);
* // explicitly turn on/off JDBC batch use
* txn.setBatchMode(true);
* txn.setBatchSize(50);
*
* // control flushing when mixing save and queries
* txn.setBatchFlushOnQuery(false);
* // control flushing when mixing save and queries
* txn.setBatchFlushOnQuery(false);
*
* // turn off persist cascade if needed
* txn.setPersistCascade(false);
* // turn off persist cascade if needed
* txn.setPersistCascade(false);
*
* // for large batch insert processing when we do not
* // ... need the generatedKeys, don't get them
* txn.setBatchGetGeneratedKeys(false);
* // for large batch insert processing when we do not
* // ... need the generatedKeys, don't get them
* txn.setBatchGetGeneratedKeys(false);
*
* // explicitly flush the JDBC batch buffer
* txn.flush();
* // explicitly flush the JDBC batch buffer
* txn.flush();
*
* ...
* ...
*
* txn.commit();
* }
* txn.commit();
* }
*
* }</pre>
* <p>
* <p>
* If you want to externalise the transaction management then you use
* createTransaction() and pass the transaction around to the various methods on
* Database yourself.
* </p>
*/
Transaction beginTransaction();
@@ -643,11 +600,9 @@ public interface Database {
/**
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
* <p>
* <p>
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
* {@link #execute(TxScope, Runnable)}.
* </p>
* <p>
*
* <h3>REQUIRES_NEW example:</h3>
* <pre>{@code
* // Start a new transaction. If there is a current transaction
@@ -694,10 +649,8 @@ public interface Database {
* This only is useful when JDBC batch is used. Flush occurs automatically when the
* transaction commits or batch size is reached. This manually flushes the JDBC batch
* buffer.
* </p>
* <p>
* This is the same as <code>currentTransaction().flush()</code>.
* </p>
*/
void flush();
@@ -717,7 +670,6 @@ public interface Database {
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* </p>
* <p>
* Code example:
* <p>
@@ -744,7 +696,6 @@ public interface Database {
* <p>
* Note that this resets OneToMany and ManyToMany properties so that if they
* are accessed a lazy load will refresh the many property.
* </p>
*/
void refresh(Object bean);
@@ -763,12 +714,11 @@ public interface Database {
* // Fetch order 1
* Order order = database.find(Order.class, 1);
* }</pre>
* <p>
*
* <p>
* If you want more control over the query then you can use createQuery() and
* Query.findOne();
* </p>
* <p>
*
* <pre>{@code
* // ... additionally fetching customer, customer shipping address,
* // order details, and the product associated with each order detail.
@@ -810,10 +760,9 @@ public interface Database {
* <p>
* This will not perform a query against the database unless some property other
* that the id property is accessed.
* </p>
* <p>
* It is most commonly used to set a 'foreign key' on another bean like:
* </p>
*
* <pre>{@code
*
* Product product = database.getReference(Product.class, 1);
@@ -853,12 +802,10 @@ public interface Database {
* <p>
* The extended API has the options for executing queries that take an explicit
* transaction as an argument.
* </p>
* <p>
* Typically we only need to use the extended API when we do NOT want to use the
* Typically, we only need to use the extended API when we do NOT want to use the
* usual ThreadLocal based mechanism to obtain the current transaction but instead
* supply the transaction explicitly.
* </p>
*/
ExtendedServer extended();
@@ -867,32 +814,27 @@ public interface Database {
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* Save can cascade along relationships. For this to happen you need to
* specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the
* OneToMany, OneToOne or ManyToMany annotation.
* </p>
* <p>
* In this example below the details property has a CascadeType.ALL set so
* saving an order will also save all its details.
* </p>
* <p>
*
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* List<OrderDetail> details;
* ...
* }
* }</pre>
* <p>
* <p>
* When a save cascades via a OneToMany or ManyToMany Ebean will automatically
* set the 'parent' object to the 'detail' object. In the example below in
* saving the order and cascade saving the order details the 'parent' order
* will be set against each order detail when it is saved.
* </p>
*/
void save(Object bean) throws OptimisticLockException;
@@ -910,16 +852,13 @@ public interface Database {
* Delete the bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*/
boolean delete(Object bean) throws OptimisticLockException;
@@ -927,12 +866,10 @@ public interface Database {
* Delete the bean with an explicit transaction.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. However, if JDBC batch mode is used then this always returns true.
* </p>
*/
boolean delete(Object bean, Transaction transaction) throws OptimisticLockException;
@@ -1014,16 +951,13 @@ public interface Database {
* <p>
* If you wish to execute a Sql Select natively then you should use the
* SqlQuery object or DtoQuery.
* </p>
* <p>
* Note that the table modification information is automatically deduced and
* you do not need to call the DB.externalModification() method when you
* use this method.
* </p>
* <p>
* Example:
* </p>
* <p>
*
* <pre>{@code
*
* // example that uses 'named' parameters
@@ -1051,7 +985,6 @@ public interface Database {
* transaction.
* <p>
* This returns the number of rows that where inserted, updated or deleted.
* </p>
*/
int execute(Update<?> update);
@@ -1065,8 +998,7 @@ public interface Database {
* For making calls to stored procedures.
* <p>
* Example:
* </p>
* <p>
*
* <pre>{@code
*
* String sql = "{call sp_order_modify(?,?,?)}";
@@ -1091,23 +1023,19 @@ public interface Database {
* <p>
* If you use database.execute(UpdateSql) then the table modification information
* is automatically deduced and you do not need to call this method yourself.
* </p>
* <p>
* This information is used to invalidate objects out of the cache and
* potentially text indexes. This information is also automatically broadcast
* across the cluster.
* </p>
* <p>
* If there is a transaction then this information is placed into the current
* transactions event information. When the transaction is committed this
* information is registered (with the transaction manager). If this
* transaction is rolled back then none of the transaction event information
* registers including the information you put in via this method.
* </p>
* <p>
* If there is NO current transaction when you call this method then this
* information is registered immediately (with the transaction manager).
* </p>
*
* @param tableName the name of the table that was modified
* @param inserted true if rows where inserted into the table
@@ -1147,7 +1075,6 @@ public interface Database {
* Note: This checks only the root bean!
* <p>
* <pre>{@code
*
* // there is a unique constraint on title
*
* Document doc = new Document();
@@ -1176,7 +1103,7 @@ public interface Database {
* // uniqueProperties > [title]
* // custom msg > property[title] value[One flew over the cuckoo's nest]
*
* }
* }
*
* }</pre>
*
@@ -1200,13 +1127,12 @@ public interface Database {
* dirty so that it is not skipped.
* <p>
* <pre>{@code
* Customer customer = database.find(Customer, id);
*
* Customer customer = database.find(Customer, id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
* database.markAsDirty(customer);
* database.save(customer);
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
* database.markAsDirty(customer);
* database.save(customer);
*
* }</pre>
*/
@@ -1219,18 +1145,17 @@ public interface Database {
* <b>Stateless updates:</b> Note that the bean does not have to be previously fetched to call
* update().You can create a new instance and set some of its properties programmatically for via
* JSON/XML marshalling etc. This is described as a 'stateless update'.
* </p>
* <p>
* <b>Optimistic Locking: </b> Note that if the version property is not set when update() is
* called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used).
* </p>
*
* <pre>{@code
*
* // A 'stateless update' example
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
* database.update(customer);
* // A 'stateless update' example
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
* database.update(customer);
*
* }</pre>
*/
@@ -1281,7 +1206,6 @@ public interface Database {
* Compared to save() this forces bean to perform an insert rather than trying to decide
* based on the bean state. As such this is useful when you fetch beans from one database
* and want to insert them into another database (and you want to explicitly insert them).
* </p>
*/
void insert(Object bean);
@@ -1314,21 +1238,18 @@ public interface Database {
/**
* Execute a Runnable in a Transaction with an explicit scope.
* <p>
* The scope can control the transaction type, isolation and rollback
* semantics.
* </p>
* <p>
* The scope can control the transaction type, isolation and rollback semantics.
*
* <pre>{@code
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* database.execute(scope, new Runnable() {
* public void run() {
* User u1 = database.find(User.class, 1);
* ...
* }
* });
* database.execute(scope, new Runnable() {
* public void run() {
* User u1 = database.find(User.class, 1);
* ...
* }
* });
*
* }</pre>
*/
@@ -1339,21 +1260,19 @@ public interface Database {
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
* </p>
* <p>
*
* <pre>{@code
* database.execute(() -> {
*
* database.execute(() -> {
* User u1 = database.find(User.class, 1);
* User u2 = database.find(User.class, 2);
*
* User u1 = database.find(User.class, 1);
* User u2 = database.find(User.class, 2);
* u1.setName("u1 mod");
* u2.setName("u2 mod");
*
* u1.setName("u1 mod");
* u2.setName("u2 mod");
*
* u1.save();
* u2.save();
* });
* u1.save();
* u2.save();
* });
*
* }</pre>
*/
@@ -1364,18 +1283,16 @@ public interface Database {
* <p>
* The scope can control the transaction type, isolation and rollback
* semantics.
* </p>
* <p>
* <pre>{@code
*
* <pre>{@code
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* database.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = database.find(User.class, 1);
* ...
* return u1.getEmail();
* public String call() {
* User u1 = database.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* });
*
@@ -1388,10 +1305,8 @@ public interface Database {
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
* </p>
* <p>
* <pre>{@code
*
* <pre>{@code
* database.executeCall(new Callable<String>() {
* public String call() {
* User u1 = database.find(User.class, 1);
@@ -1406,7 +1321,6 @@ public interface Database {
* return u1.getEmail();
* }
* });
*
* }</pre>
*/
<T> T executeCall(Callable<T> callable);
@@ -1417,8 +1331,7 @@ public interface Database {
ServerCacheManager cacheManager();
/**
* Return the BackgroundExecutor service for asynchronous processing of
* queries.
* Return the BackgroundExecutor service for asynchronous processing of queries.
*/
BackgroundExecutor backgroundExecutor();
@@ -1427,33 +1340,30 @@ public interface Database {
* <p>
* This instance is safe to be used concurrently by multiple threads and this
* method is cheap to call.
* </p>
* <p>
*
* <h3>Simple example:</h3>
* <pre>{@code
*
* JsonContext json = database.json();
* String jsonOutput = json.toJson(list);
* System.out.println(jsonOutput);
*
* JsonContext json = database.json();
* String jsonOutput = json.toJson(list);
* System.out.println(jsonOutput);
* }</pre>
*
* <p>
* <h3>Using PathProperties:</h3>
* <pre>{@code
* // specify just the properties we want
* PathProperties paths = PathProperties.parse("name, status, anniversary");
*
* // specify just the properties we want
* PathProperties paths = PathProperties.parse("name, status, anniversary");
* List<Customer> customers =
* database.find(Customer.class)
* // apply those paths to the query (only fetch what we need)
* .apply(paths)
* .where().ilike("name", "rob%")
* .findList();
*
* List<Customer> customers =
* database.find(Customer.class)
* // apply those paths to the query (only fetch what we need)
* .apply(paths)
* .where().ilike("name", "rob%")
* .findList();
*
* // ... get the json
* JsonContext jsonContext = database.json();
* String json = jsonContext.toJson(customers, paths);
* // ... get the json
* JsonContext jsonContext = database.json();
* String json = jsonContext.toJson(customers, paths);
*
* }</pre>
*
@@ -1478,7 +1388,6 @@ public interface Database {
* Publish a single bean given its type and id returning the resulting live bean.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1493,7 +1402,6 @@ public interface Database {
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1506,7 +1414,6 @@ public interface Database {
* Publish the beans that match the query returning the resulting published beans.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
@@ -1519,7 +1426,6 @@ public interface Database {
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
@@ -1531,7 +1437,6 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1546,7 +1451,6 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1560,7 +1464,6 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
@@ -1573,7 +1476,6 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
@@ -1585,7 +1487,6 @@ public interface Database {
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties/path for the given bean type.
* </p>
*/
<T> Set<String> validateQuery(Query<T> query);
@@ -1611,6 +1512,6 @@ public interface Database {
/**
* Truncate the base tables for the given bean types.
*/
void truncate(Class<?>... tables);
void truncate(Class<?>... beanTypes);
}
@@ -3,8 +3,7 @@ package io.ebean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.util.Properties;
/**
@@ -29,9 +28,11 @@ public final class EbeanVersion {
private static void readVersion() {
try {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-api/pom.properties")) {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/ebean-maven-version.txt")) {
if (in != null) {
version = readVersion(in);
try (LineNumberReader reader = new LineNumberReader(new InputStreamReader(in))) {
version = reader.readLine();
}
}
}
log.info("ebean version: {}", version);
@@ -88,7 +89,7 @@ public final class EbeanVersion {
}
/**
* Returns the ebean version (read from /META-INF/maven/io.ebean/ebean/pom.properties)
* Returns the ebean version (read from META-INF/ebean-maven-version.txt)
*/
public static String getVersion() {
return version;
@@ -383,6 +383,15 @@ public interface ExpressionList<T> {
*/
<A> List<A> findSingleAttributeList();
/**
* Executes the query returning a set of values for a single property.
* <p>
* This can be used to cache sets.
*
* @return a HashSet of values for the selegted property
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute a query returning a single value of a single property/column.
* <pre>{@code
@@ -826,6 +835,20 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> eq(String propertyName, Object value);
/**
* Is EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is the EQUAL TO equivalent to {@link #inOrEmpty(String, Collection)} where the expression/predicate
* is only added when the value is non-null.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>eqIfPresent()</code> rather than having a separate if block.
* <p>
* Another option is to instead globally use {@link io.ebean.config.DatabaseConfig#setExpressionEqualsWithNullAsNoop(boolean)}
* but that is not always desirable.
*/
ExpressionList<T> eqIfPresent(String propertyName, @Nullable Object value);
/**
* Equal To or Null - property is equal to a given value or null.
*/
@@ -368,6 +368,11 @@ public interface ExtendedServer {
*/
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
* Execute the query returning a hashset of values for a single property.
*/
<A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean or null (if no matching
* bean is found).
@@ -8,6 +8,9 @@ import java.util.List;
* Intended to be used as a base class for 'Finder' implementations that can then
* be injected or used as public static fields on the associated entity bean.
* <p>
* When using dependency injection {@link BeanRepository} and {@link BeanFinder}
* are expected to be used rather than this Finder.
* <p>
* These 'finders' are a place to organise all the finder methods for that bean type
* and specific finder methods are expected to be added (find by unique properties etc).
* </p>
@@ -54,6 +57,8 @@ import java.util.List;
*
* }</pre>
*
* @see BeanRepository
* @see BeanFinder
*/
@NonNullApi
public class Finder<I, T> {
+7 -1
View File
@@ -925,6 +925,11 @@ public interface Query<T> extends CancelableQuery {
*/
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a hashset of values for a single property.
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute a query returning a single value of a single property/column.
* <p>
@@ -1574,10 +1579,11 @@ public interface Query<T> extends CancelableQuery {
Query<T> setReadOnly(boolean readOnly);
/**
* Will be deprecated - migrate to use setBeanCacheMode(CacheMode.RECACHE).
* Deprecated - migrate to use setBeanCacheMode(CacheMode.PUT) or other CacheMode.
* <p>
* When set to true all the beans from this query are loaded into the bean cache.
*/
@Deprecated
Query<T> setLoadBeanCache(boolean loadBeanCache);
/**
@@ -6,6 +6,12 @@ import java.io.Serializable;
import java.util.Map;
import java.util.Set;
/**
* This is the object associated to every entity bean using byte code enhancement.
* <p>
* This provides per property state such as loaded state, changed state, original values
* as well as bean level dirty state etc.
*/
public interface EntityBeanIntercept extends Serializable {
/**
@@ -282,8 +288,14 @@ public interface EntityBeanIntercept extends Serializable {
*/
void markPropertyAsChanged(int propertyIndex);
/**
* Set the changed state for the given property.
*/
void setChangedProperty(int propertyIndex);
/**
* Set the changed and loaded state for the given property.
*/
void setChangeLoaded(int propertyIndex);
/**
@@ -291,6 +303,9 @@ public interface EntityBeanIntercept extends Serializable {
*/
void setEmbeddedPropertyDirty(int propertyIndex);
/**
* Set the original value for the property.
*/
void setOriginalValue(int propertyIndex, Object value);
/**
@@ -358,6 +373,9 @@ public interface EntityBeanIntercept extends Serializable {
*/
StringBuilder getLoadedPropertyKey();
/**
* Return the loaded state for all the properties.
*/
boolean[] getLoaded();
/**
@@ -385,6 +403,9 @@ public interface EntityBeanIntercept extends Serializable {
*/
void initialisedMany(int propertyIndex);
/**
* Invoke the PreGetterCallback if it has been set due to getter for the given property.
*/
void preGetterCallback(int propertyIndex);
/**
@@ -402,8 +423,14 @@ public interface EntityBeanIntercept extends Serializable {
*/
void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue);
/**
* Set the property changed state, bean dirtyState and property original value.
*/
void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue);
/**
* Set the dirty state on the bean.
*/
void setDirtyStatus();
/**
@@ -482,6 +509,9 @@ public interface EntityBeanIntercept extends Serializable {
*/
void setDeletedFromCollection(boolean deletedFromCollection);
/**
* Return true if the bean was orphan deleted from a collection.
*/
boolean isOrphanDelete();
/**
@@ -494,7 +524,10 @@ public interface EntityBeanIntercept extends Serializable {
*/
Map<String, Exception> getLoadErrors();
boolean isChangedProp(int i);
/**
* Return true if the property has its changed state set.
*/
boolean isChangedProp(int propertyIndex);
/**
* Return the MutableValueInfo for the given property or null.
@@ -6,10 +6,20 @@ import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* EntityBeanIntercept optimised for read only use.
* <p>
* For the read only use this intercept doesn't need to hold any state that is normally
* required for updates such as per property changed, loaded, dirty state, original values
* bean state etc.
*/
public class InterceptReadOnly implements EntityBeanIntercept {
private final EntityBean owner;
/**
* Create with a given entity.
*/
public InterceptReadOnly(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
}
@@ -21,7 +21,6 @@ import java.util.concurrent.locks.ReentrantLock;
* <p>
* This provides the mechanisms to support deferred fetching of reference beans
* and oldValues generation for concurrency checking.
* </p>
*/
public final class InterceptReadWrite implements EntityBeanIntercept {
@@ -32,24 +31,17 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private static final int STATE_LOADED = 2;
/**
* Used when a bean is partially filled.
* Used when a bean is partially loaded.
*/
private static final byte FLAG_LOADED_PROP = 1;
private static final byte FLAG_CHANGED_PROP = 2;
private static final byte FLAG_CHANGEDLOADED_PROP = 3;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
* Flags indicating if a property is a dirty embedded bean. Used to distinguish between an
* embedded bean being completely overwritten vs one with embedded properties that are dirty.
*/
private static final byte FLAG_EMBEDDED_DIRTY = 4;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
private static final byte FLAG_ORIG_VALUE_SET = 8;
/**
* Flags indicating if the mutable hash is set.
*/
@@ -78,10 +70,9 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private boolean readOnly;
private boolean dirty;
/**
* Flag set to disable lazy loading - typically for SQL "report" type entity beans.
* Flag set to disable lazy loading.
*/
private boolean disableLazyLoad;
/**
* Flag set when lazy loading failed due to the underlying bean being deleted in the DB.
*/
@@ -107,7 +98,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private MutableValueNext[] mutableNext;
/**
* Create a intercept with a given entity.
* Create with a given entity.
*/
public InterceptReadWrite(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
@@ -802,20 +802,6 @@ public class DatabasePlatform {
}
}
/**
* Return true if partitions exist for the given table.
*/
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
return true;
}
/**
* Return the SQL to create an initial partition for the given table.
*/
public String tablePartitionInit(String tableName, PartitionMode mode) {
return null;
}
/**
* Escapes the like string for this DB-Platform
*/
@@ -8,22 +8,43 @@ import java.util.List;
*/
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
private final String name;
private final List<MetaTimedMetric> timed = new ArrayList<>();
private final List<MetaQueryMetric> query = new ArrayList<>();
private final List<MetaCountMetric> count = new ArrayList<>();
public BasicMetricVisitor() {
this("db");
}
/**
* Construct to reset and collect everything.
*/
public BasicMetricVisitor() {
super(true, true, true, true);
public BasicMetricVisitor(String name) {
this(name, true, true, true, true);
}
/**
* Construct specifying reset and what to collect.
*/
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
public BasicMetricVisitor(String name, boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
this.name = name;
}
@Override
public String name() {
return name;
}
@Override
public ServerMetricsAsJson asJson() {
return new MetricsAsJson(this);
}
@Override
public List<MetricData> asData() {
return new MetricsAsData(this).data();
}
@Override
@@ -17,21 +17,20 @@ public interface MetaInfoManager {
ServerMetrics collectMetrics();
/**
* Collect the metrics in raw JSON form.
* <pre>{@code
*
* String metricsJson = database.getMetaInfoManager()
* .collectMetricsAsJson()
* .json();
*
* }</pre>
* Deprecated migrate to collectMetrics().asJson().
*/
ServerMetricsAsJson collectMetricsAsJson();
@Deprecated
default ServerMetricsAsJson collectMetricsAsJson() {
return collectMetrics().asJson();
}
/**
* Return the metrics as a list of MetricData.
* Deprecated migrate to collectMetrics().asData().
*/
List<MetricData> collectMetricsAsData();
@Deprecated
default List<MetricData> collectMetricsAsData() {
return collectMetrics().asData();
}
/**
* Visit the metrics resetting and collecting/reporting as desired.
@@ -1,12 +1,4 @@
package io.ebeaninternal.server.core;
import io.ebean.Database;
import io.ebean.meta.MetaCountMetric;
import io.ebean.meta.MetaMetric;
import io.ebean.meta.MetaQueryMetric;
import io.ebean.meta.MetaTimedMetric;
import io.ebean.meta.MetricData;
import io.ebean.meta.ServerMetrics;
package io.ebean.meta;
import java.util.ArrayList;
import java.util.List;
@@ -14,34 +6,26 @@ import java.util.List;
/**
* Dump the metrics into a list of MetricData.
*/
final class DumpMetricsData {
final class MetricsAsData {
private final Database database;
private final ServerMetrics metrics;
private final List<MetricData> list = new ArrayList<>();
DumpMetricsData(Database database) {
this.database = database;
MetricsAsData(ServerMetrics metrics) {
this.metrics = metrics;
}
List<MetricData> data() {
collect(database.metaInfo().collectMetrics());
return list;
}
private void collect(ServerMetrics serverMetrics) {
final List<MetaTimedMetric> timedMetrics = serverMetrics.timedMetrics();
final List<MetaCountMetric> countMetrics = serverMetrics.countMetrics();
final List<MetaQueryMetric> queryMetrics = serverMetrics.queryMetrics();
for (MetaTimedMetric metric : timedMetrics) {
for (MetaTimedMetric metric : metrics.timedMetrics()) {
add(metric);
}
for (MetaCountMetric metric : countMetrics) {
for (MetaCountMetric metric : metrics.countMetrics()) {
addCount(metric);
}
for (MetaQueryMetric metric : queryMetrics) {
for (MetaQueryMetric metric : metrics.queryMetrics()) {
addQuery(metric);
}
return list;
}
private MetricData create(MetaMetric metric) {
@@ -1,25 +1,16 @@
package io.ebeaninternal.server.core;
import io.ebean.Database;
import io.ebean.meta.MetaCountMetric;
import io.ebean.meta.MetaMetric;
import io.ebean.meta.MetaQueryMetric;
import io.ebean.meta.MetaTimedMetric;
import io.ebean.meta.ServerMetrics;
import io.ebean.meta.ServerMetricsAsJson;
import io.ebean.meta.SortMetric;
package io.ebean.meta;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Comparator;
import java.util.List;
final class DumpMetricsJson implements ServerMetricsAsJson {
final class MetricsAsJson implements ServerMetricsAsJson {
private final Database database;
private final ServerMetrics metrics;
private Appendable writer;
/**
* By default include sql and location attributes for the initial collection only.
* By default, include sql and location attributes for the initial collection only.
*/
private int includeExtraAttributes = 1;
private boolean withHeader = true;
@@ -29,8 +20,8 @@ final class DumpMetricsJson implements ServerMetricsAsJson {
private int listCounter;
private int objKeyCounter;
DumpMetricsJson(Database database) {
this.database = database;
MetricsAsJson(ServerMetrics metrics) {
this.metrics = metrics;
}
@Override
@@ -66,24 +57,24 @@ final class DumpMetricsJson implements ServerMetricsAsJson {
@Override
public String json() {
writer = new StringWriter();
collect(database.metaInfo().collectMetrics());
collect();
return writer.toString();
}
@Override
public void write(Appendable buffer) {
writer = buffer;
collect(database.metaInfo().collectMetrics());
collect();
}
private void collect(ServerMetrics serverMetrics) {
private void collect() {
try {
start();
for (MetaTimedMetric metric : serverMetrics.timedMetrics()) {
for (MetaTimedMetric metric : metrics.timedMetrics()) {
logTimed(metric);
}
List<MetaCountMetric> countMetrics = serverMetrics.countMetrics();
List<MetaCountMetric> countMetrics = metrics.countMetrics();
if (!countMetrics.isEmpty()) {
if (sortBy != null) {
countMetrics.sort(SortMetric.COUNT_NAME);
@@ -93,7 +84,7 @@ final class DumpMetricsJson implements ServerMetricsAsJson {
}
}
List<MetaQueryMetric> queryMetrics = serverMetrics.queryMetrics();
List<MetaQueryMetric> queryMetrics = metrics.queryMetrics();
if (!queryMetrics.isEmpty()) {
if (sortBy != null) {
queryMetrics.sort(sortBy);
@@ -112,7 +103,7 @@ final class DumpMetricsJson implements ServerMetricsAsJson {
if (withHeader) {
objStart();
key("db");
val(database.name());
val(metrics.name());
key("metrics");
listStart();
}
@@ -7,6 +7,21 @@ import java.util.List;
*/
public interface ServerMetrics {
/**
* Return the name of the database these metrics were obtained for.
*/
String name();
/**
* Return ServerMetricsAsJson to build the metrics as JSON content.
*/
ServerMetricsAsJson asJson();
/**
* Return the metrics as a list of MetricData.
*/
List<MetricData> asData();
/**
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
*/
@@ -0,0 +1 @@
${project.version}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</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.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>provided</scope>
</dependency>
@@ -55,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>test</scope>
</dependency>
@@ -70,7 +70,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:13.6.0</tile>
<tile>io.ebean.tile:enhancement:13.6.5</tile>
</tiles>
</configuration>
</plugin>
@@ -143,6 +143,7 @@ public class BaseQueryTuner {
switch (type) {
case COUNT:
case ATTRIBUTE:
case ATTRIBUTE_SET:
case ID_LIST:
case UPDATE:
case DELETE:
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -16,25 +16,24 @@ import java.sql.SQLException;
* <p>
* Scalar in the sense that the types are not compound types. Scalar types only
* map to a single database column.
* </p>
* <p>
* These types fall into two categories. Types that are mapped natively to JDBC
* types and the rest. Types that map to native JDBC types do not require any
* data type conversion to be persisted to the database. These are java types
* that map via java.sql.Types.
* </p>
* <p>
* Types that are not native to JDBC require some conversion. These include some
* common java types such as java.util.Date, java.util.Calendar,
* java.math.BigInteger.
* </p>
* <p>
* Note that Booleans may be native for some databases and require conversion on
* other databases.
* </p>
*/
public interface ScalarType<T> extends StringParser, StringFormatter, ScalarDataReader<T> {
/**
* Return true for types that do mutation detection based on json content.
*/
default boolean isJsonMapper() {
return false;
}
@@ -43,38 +42,40 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* Return true if this is a binary type and can not support parse() and format() from/to string.
* This allows Ebean to optimise marshalling types to string.
*/
boolean isBinaryType();
default boolean isBinaryType() {
return false;
}
/**
* Return true if this is a mutable scalar type (like hstore).
*/
boolean isMutable();
default boolean isMutable() {
return false;
}
/**
* For mutable scalarType's return true if the value is dirty.
* Non-dirty properties may be excluded from updates.
*/
boolean isDirty(Object value);
default boolean isDirty(Object value) {
return false;
}
/**
* Return the default DB column length for this type.
* <p>
* If a BeanProperty has no explicit length defined then this length should
* be assigned.
* </p>
* <p>
* This is primarily to support defining a length on Enum types (to
* supplement defining the length on the BeanProperty directly).
* </p>
*/
int getLength();
default int getLength() {
return 0;
}
/**
* Return true if the type is native to JDBC.
* <p>
* If it is native to JDBC then its values/instances do not need to be
* converted to and from an associated JDBC type.
* </p>
*/
boolean isJdbcNative();
@@ -83,16 +84,13 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* <p>
* This type should be consistent with the toJdbcType() method in converting
* the type to the appropriate type for binding to preparedStatements.
* </p>
*/
int getJdbcType();
/**
* Return the type that matches the bean property type.
* <p>
* This represents the 'logical' type rather than the JDBC type this maps
* to.
* </p>
* This represents the 'logical' type rather than the JDBC type this maps to.
*/
Class<T> getType();
@@ -104,7 +102,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
T read(DataReader reader) throws SQLException;
/**
* Ignore the reading of this value. Typically this means moving the index
* Ignore the reading of this value. Typically, this means moving the index
* position in the ResultSet.
*/
void loadIgnore(DataReader reader);
@@ -114,20 +112,16 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* <p>
* value may need to be converted from the logical bean property type to the
* JDBC type.
* </p>
*/
void bind(DataBinder binder, T value) throws SQLException;
/**
* Convert the value as necessary to the JDBC type.
* <p>
* Note that this should also match the type as per the getJdbcType()
* method.
* </p>
* Note that this should also match the type as per the getJdbcType() method.
* <p>
* This is typically used when the matching type is used in a where clause
* and we use this to ensure it is an appropriate jdbc type.
* </p>
*/
Object toJdbcType(Object value);
@@ -135,19 +129,14 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* Convert the value as necessary to the logical Bean type.
* <p>
* The type as per the bean property.
* </p>
* <p>
* This is used to automatically convert id values (typically from a string
* to a int, long or UUID).
* </p>
*/
T toBeanType(Object value);
/**
* Convert the type into a string representation.
* <p>
* Reciprocal of parse().
* </p>
*/
String formatValue(T value);
@@ -155,10 +144,8 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* Convert the type into a string representation.
* <p>
* This assumes the value is of the correct type.
* </p>
* <p>
* This is so that ScalarType also implements the StringFormatter interface.
* </p>
*/
@Override
String format(Object value);
@@ -167,10 +154,6 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* Convert the string value to the appropriate java object.
* <p>
* Mostly used to support CSV, JSON and XML parsing.
* </p>
* <p>
* Reciprocal of formatValue().
* </p>
*/
@Override
T parse(String value);
@@ -183,29 +166,32 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
/**
* Return true if the type can accept long systemTimeMillis input.
* <p>
* This is used to determine if is is sensible to use the
* This is used to determine if it is sensible to use the
* {@link #convertFromMillis(long)} method.
* </p>
* <p>
* This includes the Date, Calendar, sql Date, Time, Timestamp, JODA types
* as well as Long, BigDecimal and String (although it generally is not
* expected to parse systemTimeMillis to a String or BigDecimal).
* </p>
*/
boolean isDateTimeCapable();
default boolean isDateTimeCapable() {
return false;
}
/**
* Convert the value into a long version value.
*/
long asVersion(T value);
default long asVersion(T value) {
throw new UnsupportedOperationException();
}
/**
* Convert the systemTimeMillis into the appropriate java object.
* <p>
* For non dateTime types this will throw an exception.
* </p>
*/
T convertFromMillis(long dateTime);
default T convertFromMillis(long dateTime) {
throw new UnsupportedOperationException();
}
/**
* Read the value from binary input.
@@ -215,7 +201,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
/**
* Write the value to binary output.
*/
void writeData(DataOutput dataOutput, T v) throws IOException;
void writeData(DataOutput dataOutput, T value) throws IOException;
/**
* Read the value from JsonParser.
+8 -8
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.6.3</version>
<version>13.6.6</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.6.3</tag>
<tag>ebean-parent-13.6.6</tag>
</scm>
<dependencies>
@@ -41,19 +41,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
</dependency>
<dependency>
@@ -144,21 +144,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.6.3</version>
<version>13.6.6</version>
<scope>test</scope>
</dependency>
@@ -92,6 +92,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false),
/**
* Find single attribute set.
*/
ATTRIBUTE_SET(FIND_ATTRIBUTE_SET, "findAttributeSet", false, false),
/**
* Find rowCount.
*/
@@ -28,6 +28,7 @@ public interface TxnProfileEventCodes {
String FIND_ID_LIST = "fi";
String FIND_EXISTS = "ex";
String FIND_ATTRIBUTE = "fa";
String FIND_ATTRIBUTE_SET = "fas";
String FIND_COUNT = "fc";
String FIND_SUBQUERY = "fs";
@@ -33,4 +33,6 @@ public interface SpiJsonReader {
void beanVisitor(Object bean, Map<String, Object> unmappedProperties);
Object readValueUsingObjectMapper(Class<?> propertyType) throws IOException;
boolean isIntercept();
}
@@ -199,7 +199,7 @@ final class DefaultBeanLoader {
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
if (draft) {
query.asDraft();
} else if (mode == SpiQuery.Mode.LAZYLOAD_BEAN) {
} else if (mode == SpiQuery.Mode.LAZYLOAD_BEAN && desc.isSoftDelete()) {
query.setIncludeSoftDeletes();
}
if (embeddedOwnerIndex > -1) {
@@ -47,19 +47,9 @@ final class DefaultMetaInfoManager implements MetaInfoManager {
return visitBasic();
}
@Override
public ServerMetricsAsJson collectMetricsAsJson() {
return new DumpMetricsJson(server);
}
@Override
public List<MetricData> collectMetricsAsData() {
return new DumpMetricsData(server).data();
}
@Override
public BasicMetricVisitor visitBasic() {
BasicMetricVisitor basic = new BasicMetricVisitor();
BasicMetricVisitor basic = new BasicMetricVisitor(server.name());
visitMetrics(basic);
return basic;
}
@@ -1186,14 +1186,34 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings("unchecked")
public <A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ATTRIBUTE, query, transaction);
SpiOrmQueryRequest<T> request = buildQueryRequest(Type.ATTRIBUTE, query, transaction);
request.query().setSingleAttribute();
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
return (List<A>) result;
}
try {
request.initTransIfRequired();
return request.findSingleAttributeList();
return request.findSingleAttributeCollection(new ArrayList<>());
} finally {
request.endTransIfRequired();
}
}
@Override
@SuppressWarnings("unchecked")
public <A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest<T> request = buildQueryRequest(Type.ATTRIBUTE_SET, query, transaction);
request.query().setSingleAttribute();
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
return (Set<A>) result;
}
try {
request.initTransIfRequired();
return request.findSingleAttributeCollection(new LinkedHashSet<>());
} finally {
request.endTransIfRequired();
}
@@ -6,6 +6,7 @@ import io.ebean.bean.BeanCollection;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
/**
@@ -29,9 +30,9 @@ public interface OrmQueryEngine {
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
/**
* Execute the findSingleAttributeList query.
* Execute the findSingleAttributeCollection query.
*/
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
<A extends Collection<?>> A findSingleAttributeCollection(OrmQueryRequest<?> request, A collection);
/**
* Execute the findVersions query.
@@ -431,8 +431,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
}
@Override
public <A> List<A> findSingleAttributeList() {
return queryEngine.findSingleAttributeList(this);
public <A extends Collection<?>> A findSingleAttributeCollection(A collection) {
return queryEngine.findSingleAttributeCollection(this, collection);
}
/**
@@ -458,8 +458,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
/**
* Return the many property that is fetched in the query or null if there is not one.
*/
public BeanPropertyAssocMany<?> manyProperty() {
return manyProperty;
public BeanPropertyAssocMany<?> manyPropertyForOrderBy() {
return query.isSingleAttribute() ? null : manyProperty;
}
/**
@@ -77,8 +77,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
private List<BeanPropertyAssocMany<?>> updatedManys;
/**
* Need to get and store the updated properties because the persist listener is notified
* later on a different thread and the bean has been reset at that point.
* Store the updated properties to notify persist listener.
*/
private Set<String> updatedProperties;
/**
@@ -122,7 +121,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
private boolean complete;
/**
* Many to many intersection table changes that are held for later batch processing.
* Many-to-many intersection table changes that are held for later batch processing.
*/
private List<SaveMany> saveMany;
@@ -148,9 +147,10 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
// 'stateless update' - set loaded properties as dirty
intercept.setNewBeanForUpdate();
statelessUpdate = true;
} else if (!intercept.isDirty()) {
// check if any mutable scalar properties are dirty
beanDescriptor.checkAnyMutableProperties(intercept);
}
// Mark Mutable scalar properties (like Hstore) as dirty where necessary
beanDescriptor.checkMutableProperties(intercept);
}
this.concurrencyMode = beanDescriptor.concurrencyMode(intercept);
this.publish = Flags.isPublish(flags);
@@ -726,10 +726,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
executeInsert();
return -1;
case UPDATE:
if (beanPersistListener != null) {
// store the updated properties for sending later
updatedProperties = updatedProperties();
}
executeUpdate();
return -1;
case DELETE_SOFT:
@@ -1208,6 +1204,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
private void executeUpdate() {
setTenantId();
if (controller == null || controller.preUpdate(this)) {
// check dirty state for all mutable scalar properties (like DbJson, Hstore)
beanDescriptor.checkAllMutableProperties(intercept);
if (beanPersistListener != null) {
updatedProperties = updatedProperties();
}
postControllerPrepareUpdate();
beanManager.getBeanPersister().update(this);
}
@@ -7,6 +7,7 @@ import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeanservice.docstore.api.DocQueryRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -122,7 +123,7 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
/**
* Execute the findSingleAttributeList query.
*/
<A> List<A> findSingleAttributeList();
<A extends Collection<?>> A findSingleAttributeCollection(A collection);
/**
* Execute returning the ResultSet.
@@ -13,11 +13,10 @@ public interface DataTimeZone {
Calendar getTimeZone();
/**
* Return the Calendar to use for Timezone information when reading/writing date.
* A 'date' only value has normally no timezone information, but some platforms (like MySQL)
* reqire this.
* Return the Calendar to use for Timezone information when reading/writing a time component (date only/time only).
* A time component has normally no timezone information, but some platforms (like MySQL) reqire this.
*/
default Calendar getDateTimeZone() {
default Calendar getTimeComponentTimeZone() {
return null;
}
}
@@ -19,7 +19,7 @@ public class MySqlDataTimeZone implements DataTimeZone {
}
@Override
public Calendar getDateTimeZone() {
public Calendar getTimeComponentTimeZone() {
return zone;
}
}
@@ -3140,9 +3140,9 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
/**
* Check for mutable scalar types and mark as dirty if necessary.
* Check all mutable scalar types and mark as dirty if necessary.
*/
public void checkMutableProperties(EntityBeanIntercept ebi) {
public void checkAllMutableProperties(EntityBeanIntercept ebi) {
for (BeanProperty beanProperty : propertiesMutable) {
int propertyIndex = beanProperty.propertyIndex();
if (ebi.isLoadedProperty(propertyIndex)) {
@@ -3156,6 +3156,23 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
}
/**
* Return true if any mutable properties are dirty.
*/
public boolean checkAnyMutableProperties(EntityBeanIntercept ebi) {
for (BeanProperty beanProperty : propertiesMutable) {
int propertyIndex = beanProperty.propertyIndex();
if (ebi.isLoadedProperty(propertyIndex)) {
Object value = beanProperty.getValue(ebi.getOwner());
if (beanProperty.checkMutable(value, ebi.isDirtyProperty(propertyIndex), ebi)) {
ebi.markPropertyAsChanged(propertyIndex);
return true;
}
}
}
return false;
}
public ConcurrencyMode concurrencyMode(EntityBeanIntercept ebi) {
if (!hasVersionProperty(ebi)) {
return ConcurrencyMode.NONE;
@@ -1414,7 +1414,11 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
JsonToken event = ctx.nextToken();
if (JsonToken.VALUE_NULL == event) {
if (jsonDeserialize) {
setValue(bean, null);
if (ctx.isIntercept()) {
setValueIntercept(bean, null);
} else {
setValue(bean, null);
}
}
} else {
// expect to read non-null json value
@@ -1433,7 +1437,11 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
}
if (jsonDeserialize) {
setValue(bean, objValue);
if (ctx.isIntercept()) {
setValueIntercept(bean, objValue);
} else {
setValue(bean, objValue);
}
}
}
}
@@ -50,7 +50,11 @@ class BeanPropertyAssocManyJsonHelp {
if (JsonToken.START_ARRAY != event && JsonToken.START_OBJECT != event) {
throw new JsonParseException(parser, "Unexpected token " + event + " - expecting start array or object");
}
many.setValue(parentBean, many.jsonReadCollection(readJson, parentBean));
if (readJson.isIntercept()) {
many.setValueIntercept(parentBean, many.jsonReadCollection(readJson, parentBean));
} else {
many.setValue(parentBean, many.jsonReadCollection(readJson, parentBean));
}
}
/**
@@ -785,7 +785,11 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
if (jsonDeserialize && targetDescriptor != null) {
T target = (T) value(bean);
T assocBean = targetDescriptor.jsonRead(readJson, name, target);
setValue(bean, assocBean);
if (readJson.isIntercept()) {
setValueIntercept(bean, assocBean);
} else {
setValue(bean, assocBean);
}
}
}
@@ -6,7 +6,6 @@ import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.query.STreePropertyAssocMany;
import java.util.Map;
@@ -70,11 +69,6 @@ public interface DbReadContext {
*/
void register(BeanPropertyAssocMany<?> many, BeanCollection<?> bc);
/**
* Return the property that is associated with the many. There can only be
* one. This can be null.
*/
STreePropertyAssocMany getManyProperty();
/**
* Set back the bean that has just been loaded with its id.
@@ -46,20 +46,29 @@ final class DtoMetaBuilder {
}
static String propertyName(String methodName) {
final String name = methodName.substring(3);
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
if (isTraditionalSetterMethod(methodName)) {
final String name = methodName.substring(3);
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
} else {
// accessor style setter method
return methodName;
}
}
private static boolean isTraditionalSetterMethod(String methodName) {
return methodName.startsWith("set") && methodName.length() > 3 && Character.isUpperCase(methodName.charAt(3));
}
/**
* Include a public "setter" method - 1 argument, returns void.
*/
static boolean includeMethod(Method method) {
String name = method.getName();
final int modifiers = method.getModifiers();
return Modifier.isPublic(modifiers)
&& !Modifier.isStatic(modifiers)
&& Void.TYPE.equals(method.getReturnType())
&& method.getParameterTypes().length == 1
&& method.getName().startsWith("set") && method.getName().length() > 3;
&& (!name.equals("wait") && !name.equals("equals"));
}
private void readConstructors() {
@@ -467,6 +467,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.findSingleAttributeList();
}
@Override
public <A> Set<A> findSingleAttributeSet() {
return query.findSingleAttributeSet();
}
@Override
public boolean exists() {
return query.exists();
@@ -793,6 +798,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return add(expr.eq(propertyName, value));
}
@Override
public ExpressionList<T> eqIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : add(expr.eq(propertyName, value));
}
@Override
public ExpressionList<T> eqOrNull(String propertyName, Object value) {
return add(expr.eqOrNull(propertyName, value));
@@ -309,6 +309,11 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.eq(propertyName, value);
}
@Override
public ExpressionList<T> eqIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : exprList.eq(propertyName, value);
}
@Override
public ExpressionList<T> eqOrNull(String propertyName, Object value) {
return exprList.eqOrNull(propertyName, value);
@@ -464,6 +469,11 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.findSingleAttributeList();
}
@Override
public <A> Set<A> findSingleAttributeSet() {
return exprList.findSingleAttributeSet();
}
@Override
public PagedList<T> findPagedList() {
return exprList.findPagedList();
@@ -101,7 +101,7 @@ public final class DLoadContext implements LoadContext {
this.useDocStore = query.isUseDocStore();
this.asOf = query.getAsOf();
this.asDraft = query.isAsDraft();
this.includeSoftDeletes = query.isIncludeSoftDeletes();
this.includeSoftDeletes = query.isIncludeSoftDeletes() && query.getMode() == SpiQuery.Mode.NORMAL;
this.readOnly = query.isReadOnly();
this.disableReadAudit = query.isDisableReadAudit();
this.disableLazyLoading = query.isDisableLazyLoading();
@@ -234,7 +234,7 @@ public final class DLoadContext implements LoadContext {
}
}
protected SpiEbeanServer getEbeanServer() {
SpiEbeanServer getEbeanServer() {
return ebeanServer;
}
@@ -242,7 +242,7 @@ public final class DLoadContext implements LoadContext {
* Return the parent state which defines the sharedInstance and readOnly status
* which needs to be propagated to other beans and collections.
*/
protected Boolean isReadOnly() {
Boolean isReadOnly() {
return readOnly;
}
@@ -283,7 +283,7 @@ public final class DLoadContext implements LoadContext {
DLoadBeanContext getBeanContextWithInherit(String path, BeanPropertyAssocOne<?> property) {
String key = path + ":" + property.targetDescriptor().name();
return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path, null));
return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path));
}
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
@@ -313,8 +313,8 @@ public final class DLoadContext implements LoadContext {
return new DLoadBeanContext(this, p.targetDescriptor(), path, queryProps);
}
private DLoadBeanContext createBeanContext(BeanPropertyAssoc<?> property, String path, OrmQueryProperties queryProps) {
return new DLoadBeanContext(this, property.targetDescriptor(), path, queryProps);
private DLoadBeanContext createBeanContext(BeanPropertyAssoc<?> property, String path) {
return new DLoadBeanContext(this, property.targetDescriptor(), path, null);
}
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path) {
@@ -126,7 +126,7 @@ final class SaveManyBeans extends SaveManyBase {
// performance optimisation for large collections
targetDescriptor.preAllocateIds(collection.size());
}
if (!insertedParent && many.isOrphanRemoval() && request.isForcedUpdate()) {
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
@@ -140,6 +140,10 @@ final class SaveManyBeans extends SaveManyBase {
transaction.depth(-1);
}
private boolean forcedUpdateOrphanRemoval() {
return !insertedParent && many.isOrphanRemoval() && request.isForcedUpdate();
}
private void saveAllBeans(final BeanProperty orderColumn) {
Object mapKeyValue = null;
boolean skipSavingThisBean;
@@ -340,7 +344,7 @@ final class SaveManyBeans extends SaveManyBase {
return;
}
if (!(value instanceof BeanCollection<?>)) {
if (!insertedParent && cascade && isChangedProperty()) {
if (!forcedUpdateOrphanRemoval() && (!insertedParent && cascade && isChangedProperty())) {
persister.addToFlushQueue(many.deleteByParentId(request.beanId(), null), transaction, 0);
insertAllChildren = true;
}
@@ -605,14 +605,6 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
return logWhereSql;
}
/**
* Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null.
*/
@Override
public STreePropertyAssocMany getManyProperty() {
return manyProperty;
}
public String getBindLog() {
return bindLog;
@@ -178,7 +178,6 @@ final class CQueryBuilder {
CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest<?> request) {
SpiQuery<?> query = request.query();
query.setSingleAttribute();
if (!query.isIncludeSoftDeletes()) {
BeanDescriptor<?> desc = request.descriptor();
if (desc.isSoftDelete()) {
@@ -561,7 +560,7 @@ final class CQueryBuilder {
if (selectClause != null) {
sb.append(selectClause);
} else {
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null);
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && (select.getManyProperty() == null || query.isSingleAttribute()));
if (!useSqlLimiter) {
appendSelectDistinct();
}
@@ -24,11 +24,7 @@ import org.slf4j.Logger;
import javax.persistence.PersistenceException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Handles the Object Relational fetching.
@@ -91,16 +87,16 @@ public final class CQueryEngine {
/**
* Build and execute the findSingleAttributeList query.
*/
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
public <A extends Collection<?>> A findSingleAttributeList(OrmQueryRequest<?> request, A collection) {
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request);
request.setCancelableQuery(rcQuery);
return findAttributeList(request, rcQuery);
return findAttributeCollection(request, rcQuery, collection);
}
@SuppressWarnings("unchecked")
private <A> List<A> findAttributeList(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery) {
private <A extends Collection<?>> A findAttributeCollection(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery, A collection) {
try {
List<A> list = (List<A>) rcQuery.findList();
rcQuery.findCollection(collection);
if (request.logSql()) {
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog(), rcQuery.micros());
}
@@ -109,13 +105,21 @@ public final class CQueryEngine {
}
if (request.isQueryCachePut()) {
request.addDependentTables(rcQuery.getDependentTables());
list = Collections.unmodifiableList(list);
request.putToQueryCache(list);
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
list = new ArrayList<>(list);
if (collection instanceof List) {
collection = (A) Collections.unmodifiableList((List<?>) collection);
request.putToQueryCache(collection);
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
collection = (A) new ArrayList<>(collection);
}
} else if (collection instanceof Set) {
collection = (A) Collections.unmodifiableSet((Set<?>) collection);
request.putToQueryCache(collection);
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
collection = (A) new LinkedHashSet<>(collection);
}
}
}
return list;
return collection;
} catch (SQLException e) {
throw translate(request, rcQuery.getBindLog(), rcQuery.getGeneratedSql(), e);
}
@@ -144,7 +148,7 @@ public final class CQueryEngine {
public <A> List<A> findIds(OrmQueryRequest<?> request) {
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request);
request.setCancelableQuery(rcQuery);
return findAttributeList(request, rcQuery);
return findAttributeCollection(request, rcQuery, new ArrayList<>());
}
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog, long micros) {
@@ -16,6 +16,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
@@ -76,11 +77,10 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca
/**
* Execute the query returning the row count.
*/
List<Object> findList() throws SQLException {
void findCollection(Collection result) throws SQLException {
long startNano = System.nanoTime();
try {
prepareExecute();
List<Object> result = new ArrayList<>();
while (dataReader.next()) {
Object value = reader.read(dataReader);
if (containsCounts) {
@@ -95,7 +95,6 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
}
getTransaction().profileEvent(this);
return result;
} finally {
close();
}
@@ -225,7 +225,7 @@ public final class CQueryPredicates {
*/
private void parsePropertiesToDbColumns(DeployParser deployParser) {
// order by is dependent on the manyProperty (if there is one)
String logicalOrderBy = deriveOrderByWithMany(request.manyProperty());
String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy());
if (logicalOrderBy != null) {
dbOrderBy = deployParser.parse(logicalOrderBy);
}
@@ -234,7 +234,7 @@ public final class CQueryPredicates {
dbWhere = deriveWhere(deployParser);
dbFilterMany = deriveFilterMany(deployParser);
dbHaving = deriveHaving(deployParser);
// all includes including ones for manyWhere clause
// all includes, including ones for manyWhere clause
predicateIncludes = deployParser.getIncludes();
}
@@ -293,8 +293,7 @@ public final class CQueryPredicates {
}
/**
* There is a many property so we need to make sure the ordering is
* appropriate.
* There is a many property we need to make sure the ordering is appropriate.
*/
private String deriveOrderByWithMany(BeanPropertyAssocMany<?> manyProp) {
if (manyProp == null) {
@@ -286,6 +286,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public <A> Set<A> findSingleAttributeSet() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Override
public <A> A findSingleAttribute() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -17,6 +17,7 @@ import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* Main Finder implementation.
@@ -97,9 +98,9 @@ public final class DefaultOrmQueryEngine implements OrmQueryEngine {
}
@Override
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
public <A extends Collection<?>> A findSingleAttributeCollection(OrmQueryRequest<?> request, A collection) {
flushJdbcBatchOnQuery(request);
return queryEngine.findSingleAttributeList(request);
return queryEngine.findSingleAttributeList(request, collection);
}
@Override
@@ -36,6 +36,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
private final SpiQuery.TemporalMode temporalMode;
private final boolean temporalVersions;
final IdBinder lazyLoadParentIdBinder;
private final STreePropertyAssocMany loadingChildProperty;
SqlTreeLoadBean(SqlTreeNodeBean node) {
this.lazyLoadParent = node.lazyLoadParent;
@@ -55,6 +56,16 @@ class SqlTreeLoadBean implements SqlTreeLoad {
this.properties = node.properties;
this.pathMap = node.pathMap;
this.children = node.createLoadChildren();
this.loadingChildProperty = loadingChildProperty();
}
private STreePropertyAssocMany loadingChildProperty() {
for (SqlTreeLoad child : children) {
if (child instanceof SqlTreeLoadManyRoot) {
return ((SqlTreeLoadManyRoot) child).manyProp();
}
}
return null;
}
boolean isRoot() {
@@ -259,6 +270,9 @@ class SqlTreeLoadBean implements SqlTreeLoad {
if (disableLazyLoad) {
// bean does not have an Id or is SqlSelect based
ebi.setDisableLazyLoad(true);
if (!partialObject) {
ebi.setFullyLoadedBean(true);
}
} else if (partialObject) {
if (readId) {
// register for lazy loading
@@ -280,10 +294,9 @@ class SqlTreeLoadBean implements SqlTreeLoad {
* included in the actual query.
*/
private void createListProxies() {
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
if (many != loadingChildProperty) {
if (readOnlyNoIntercept) {
many.createEmptyReference(localBean);
} else {
@@ -352,7 +365,7 @@ class SqlTreeLoadBean implements SqlTreeLoad {
* context we need to check if it is already contained in the collection.
*/
final boolean isContextBean() {
return localBean == null;
return localBean == null || queryMode == Mode.LAZYLOAD_BEAN;
}
}
@@ -14,6 +14,10 @@ final class SqlTreeLoadManyRoot extends SqlTreeLoadBean {
this.manyProp = node.manyProp;
}
STreePropertyAssocMany manyProp() {
return manyProp;
}
@Override
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
// pass in null for parentBean because added to a collection rather than set to the parentBean
@@ -15,7 +15,10 @@ import io.ebeaninternal.server.autotune.ProfilingListener;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.*;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.expression.*;
import io.ebeaninternal.server.expression.DefaultExpressionList;
import io.ebeaninternal.server.expression.IdInExpression;
import io.ebeaninternal.server.expression.InExpression;
import io.ebeaninternal.server.expression.SimpleExpression;
import io.ebeaninternal.server.query.NativeSqlQueryPlanKey;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.transaction.ExternalJdbcTransaction;
@@ -504,7 +507,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
if (Mode.LAZYLOAD_MANY == mode) {
return false;
} else {
return !hasMaxRowsOrFirstRow() || isRawSql();
return singleAttribute || !hasMaxRowsOrFirstRow() || isRawSql();
}
}
@@ -593,6 +596,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
// clear select and fetch joins
detail.clear();
select(beanDescriptor.idSelect());
singleAttribute = true;
}
@Override
@@ -636,7 +640,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
if (singleExpression instanceof IdInExpression) {
return new CacheIdLookupMany<>((IdInExpression) singleExpression);
} else if (singleExpression instanceof InExpression) {
InExpression in = (InExpression)singleExpression;
InExpression in = (InExpression) singleExpression;
if (in.property().equals(beanDescriptor.idName())) {
return new CacheIdLookupMany<>(in);
}
@@ -1270,7 +1274,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
@Override
public final Query<T> setLoadBeanCache(boolean loadBeanCache) {
this.useBeanCache = CacheMode.PUT;
this.useBeanCache = loadBeanCache ? CacheMode.PUT : CacheMode.OFF;
return this;
}
@@ -1498,6 +1502,11 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return (List<A>) server.findSingleAttributeList(this, transaction);
}
@Override
public final <A> Set<A> findSingleAttributeSet() {
return (Set<A>) server.findSingleAttributeSet(this, transaction);
}
@Override
public final <A> A findSingleAttribute() {
List<A> list = findSingleAttributeList();
@@ -125,7 +125,7 @@ public final class DJsonContext implements SpiJsonContext {
BeanDescriptor<T> desc = getDescriptor(cls);
try {
return desc.jsonRead(new ReadJson(desc, parser, options, determineObjectMapper(options)), null, null);
return desc.jsonRead(new ReadJson(desc, parser, options, determineObjectMapper(options), false), null, null);
} catch (IOException e) {
throw new JsonIOException(e);
}
@@ -158,10 +158,10 @@ public final class DJsonContext implements SpiJsonContext {
@Override
public <T> void toBean(T target, JsonParser parser, JsonReadOptions options) throws JsonIOException {
BeanDescriptor<T> desc = (BeanDescriptor<T>) getDescriptor(target.getClass());
try {
desc.jsonRead(new ReadJson(desc, parser, options, determineObjectMapper(options)), null, target);
desc.jsonRead(new ReadJson(desc, parser, options, determineObjectMapper(options), target != null), null, target);
} catch (IOException e) {
throw new JsonIOException(e);
}
@@ -171,14 +171,14 @@ public final class DJsonContext implements SpiJsonContext {
public <T> DJsonBeanReader<T> createBeanReader(Class<T> cls, JsonParser parser, JsonReadOptions options) throws JsonIOException {
BeanDescriptor<T> desc = getDescriptor(cls);
return new DJsonBeanReader<>(desc, new ReadJson(desc, parser, options, determineObjectMapper(options)));
return new DJsonBeanReader<>(desc, new ReadJson(desc, parser, options, determineObjectMapper(options), false));
}
@Override
public <T> DJsonBeanReader<T> createBeanReader(BeanType<T> beanType, JsonParser parser, JsonReadOptions options) throws JsonIOException {
BeanDescriptor<T> desc = (BeanDescriptor<T>) beanType;
SpiJsonReader readJson = new ReadJson(desc, parser, options, determineObjectMapper(options));
SpiJsonReader readJson = new ReadJson(desc, parser, options, determineObjectMapper(options), false);
return new DJsonBeanReader<>(desc, readJson);
}
@@ -211,7 +211,7 @@ public final class DJsonContext implements SpiJsonContext {
public <T> List<T> toList(Class<T> cls, JsonParser src, JsonReadOptions options) throws JsonIOException {
BeanDescriptor<T> desc = getDescriptor(cls);
SpiJsonReader readJson = new ReadJson(desc, src, options, determineObjectMapper(options));
SpiJsonReader readJson = new ReadJson(desc, src, options, determineObjectMapper(options), false);
try {
JsonToken currentToken = src.getCurrentToken();
@@ -225,7 +225,7 @@ public final class DJsonContext implements SpiJsonContext {
List<T> list = new ArrayList<>();
do {
// CHECKME: Should we update the list
T bean = desc.jsonRead(readJson, null, null);
T bean = desc.jsonRead(readJson, null, null);
if (bean == null) {
break;
} else {
@@ -395,7 +395,7 @@ public final class DJsonContext implements SpiJsonContext {
BeanDescriptor<?> desc = (BeanDescriptor<?>) beanType;
JsonParser parser = createParser(new StringReader(json));
return new ReadJson(desc, parser, null, defaultObjectMapper);
return new ReadJson(desc, parser, null, defaultObjectMapper, false);
}
@Override
@@ -32,11 +32,12 @@ public final class ReadJson implements SpiJsonReader {
private final Object objectMapper;
private final PersistenceContext persistenceContext;
private final LoadContext loadContext;
private final boolean intercept;
/**
* Construct with parser and readOptions.
*/
public ReadJson(BeanDescriptor<?> desc, JsonParser parser, JsonReadOptions readOptions, Object objectMapper) {
public ReadJson(BeanDescriptor<?> desc, JsonParser parser, JsonReadOptions readOptions, Object objectMapper, boolean intercept) {
this.rootDesc = desc;
this.parser = parser;
this.objectMapper = objectMapper;
@@ -45,6 +46,7 @@ public final class ReadJson implements SpiJsonReader {
// only create visitorMap, pathStack if needed ...
this.visitorMap = (readOptions == null) ? null : readOptions.getVisitorMap();
this.pathStack = (visitorMap == null && loadContext == null) ? null : new PathStack();
this.intercept = intercept;
}
/**
@@ -58,6 +60,7 @@ public final class ReadJson implements SpiJsonReader {
this.objectMapper = source.objectMapper;
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
this.intercept = source.intercept;
}
private LoadContext initLoadContext(BeanDescriptor<?> desc, JsonReadOptions readOptions) {
@@ -203,4 +206,11 @@ public final class ReadJson implements SpiJsonReader {
return getObjectMapper().readValue(parser, propertyType);
}
/**
* Do we have to set values via intercept or not.
*/
@Override
public boolean isIntercept() {
return intercept;
}
}
@@ -158,7 +158,7 @@ public class DataBind implements DataBinder {
@Override
public final void setDate(java.sql.Date v) throws SQLException {
Calendar timeZone = dataTimeZone.getDateTimeZone();
Calendar timeZone = dataTimeZone.getTimeComponentTimeZone();
if (timeZone != null) {
pstmt.setDate(++pos, v, timeZone);
} else {
@@ -178,7 +178,7 @@ public class DataBind implements DataBinder {
@Override
public final void setTime(Time v) throws SQLException {
Calendar timeZone = dataTimeZone.getTimeZone();
Calendar timeZone = dataTimeZone.getTimeComponentTimeZone();
if (timeZone != null) {
pstmt.setTime(++pos, v, timeZone);
} else {
@@ -353,6 +353,9 @@ public final class DefaultTypeManager implements TypeManager {
Type genericType = prop.getGenericType();
boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop);
if (type.equals(String.class)) {
return ScalarTypeJsonString.typeFor(postgres, dbType);
}
if (type.equals(List.class)) {
DocPropertyType docType = getDocType(genericType);
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
@@ -107,7 +107,7 @@ public class RsetDataReader implements DataReader {
@Override
public final Date getDate() throws SQLException {
Calendar cal = dataTimeZone.getDateTimeZone();
Calendar cal = dataTimeZone.getTimeComponentTimeZone();
if (cal != null) {
return rset.getDate(pos(), cal);
} else {
@@ -156,7 +156,7 @@ public class RsetDataReader implements DataReader {
@Override
public final Time getTime() throws SQLException {
Calendar cal = dataTimeZone.getTimeZone();
Calendar cal = dataTimeZone.getTimeComponentTimeZone();
if (cal != null) {
return rset.getTime(pos(), cal);
} else {
@@ -18,41 +18,6 @@ abstract class ScalarTypeBase<T> implements ScalarType<T> {
this.jdbcType = jdbcType;
}
@Override
public long asVersion(T value) {
throw new RuntimeException("not supported");
}
@Override
public boolean isBinaryType() {
// override for binary/byte based types
return false;
}
/**
* Default implementation of mutable false.
*/
@Override
public boolean isMutable() {
return false;
}
/**
* Default to true.
*/
@Override
public boolean isDirty(Object value) {
return true;
}
/**
* Just return 0.
*/
@Override
public int getLength() {
return 0;
}
@Override
public boolean isJdbcNative() {
return jdbcNative;
@@ -88,16 +88,6 @@ abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
return format(value);
}
@Override
public T convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
@SuppressWarnings("unchecked")
public String format(Object value) {
@@ -234,7 +234,6 @@ public final class ScalarTypeBoolean {
@Override
public int getLength() {
// typically this will return 1
return Math.max(trueValue.length(), falseValue.length());
}
@@ -329,16 +328,6 @@ public final class ScalarTypeBoolean {
return Boolean.valueOf(value);
}
@Override
public Boolean convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public Boolean readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
@@ -85,16 +85,6 @@ final class ScalarTypeByte extends ScalarTypeBase<Byte> {
throw new TextException("Not supported");
}
@Override
public Byte convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public Byte readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
@@ -59,16 +59,6 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase<byte[]> {
throw new TextException("Not supported");
}
@Override
public byte[] convertFromMillis(long systemTimeMillis) {
throw new TextException("Not supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public byte[] readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
@@ -26,26 +26,11 @@ public final class ScalarTypeBytesEncrypted implements ScalarType<byte[]> {
this.dataEncryptSupport = dataEncryptSupport;
}
@Override
public long asVersion(byte[] value) {
throw new RuntimeException("not supported");
}
@Override
public boolean isBinaryType() {
return true;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public boolean isDirty(Object value) {
return false;
}
@Override
public void bind(DataBinder binder, byte[] value) throws SQLException {
value = dataEncryptSupport.encrypt(value);
@@ -93,16 +93,6 @@ class ScalarTypeDuration extends ScalarTypeBase<Duration> {
return Duration.parse(value);
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public Duration convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public Duration jsonRead(JsonParser parser) throws IOException {
return Duration.parse(parser.getValueAsString());
@@ -30,11 +30,6 @@ public final class ScalarTypeEncryptedWrapper<T> implements ScalarType<T>, Local
return dataEncryptSupport.encryptObject(formatValue);
}
@Override
public long asVersion(T value) {
throw new RuntimeException("not supported");
}
@Override
public boolean isBinaryType() {
return wrapped.isBinaryType();
@@ -229,16 +229,6 @@ final class ScalarTypeEnumStandard {
return Enum.valueOf(enumType, value);
}
@Override
public Object convertFromMillis(long systemTimeMillis) {
throw new TextException("Not Supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public Object jsonRead(JsonParser parser) throws IOException {
if (parser.getCodec() != null) {
@@ -39,16 +39,6 @@ class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase implemen
return enumType == null;
}
@Override
public long asVersion(Object value) {
throw new RuntimeException("not supported");
}
@Override
public boolean isBinaryType() {
return false;
}
/**
* Return the IN values for DB constraint construction.
*/
@@ -129,16 +129,6 @@ final class ScalarTypeFile extends ScalarTypeBase<File> {
throw new TextException("Not supported");
}
@Override
public File convertFromMillis(long systemTimeMillis) {
throw new TextException("Not supported");
}
@Override
public boolean isDateTimeCapable() {
return false;
}
@Override
public File readData(DataInput dataInput) throws IOException {
// skip reading large file

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