Compare commits

..
Author SHA1 Message Date
rob bygrave 4509c6b1ed [maven-release-plugin] prepare release ebean-11.37.1 2019-04-12 13:38:41 +12:00
rob bygrave d32559baf4 #1674 - For ProfileLocation use in constructors trim label <init> to init .... (for safe label) 2019-04-12 02:25:05 +12:00
rob bygrave 2639e799c5 #1673 - ENH: Support ProfileLocation on DtoQuery including via orm query.asDto() 2019-04-12 02:01:01 +12:00
rob bygrave 46c66b7169 #1672 - ENH: Add ebean.dumpMetricsOnShutdown=true ... for dumping metrics 2019-04-12 00:55:39 +12:00
rob bygrave 30ae435f33 #1672 - ENH: Add ebean.dumpMetricsOnShutdown=true ... for dumping metrics 2019-04-12 00:45:00 +12:00
rob bygrave 4f4743807c #1671 - Use table alias with delete query for Postgres, Oracle, MySql 2019-04-10 01:25:43 +12:00
rob bygrave 7b7a492241 Bump to 11.37.1 2019-04-09 23:04:34 +12:00
rob bygrave 4af8e53315 #1670 - Expose metrics as ServerMetrics interface (improvement over existing BasicMetricVisitor use) 2019-04-09 22:54:16 +12:00
rob bygrave 1c6fa575f2 #1669 - When deleting complex object graphs, entities are deleted multiple times
Fix by not unregistering the deleted bean hash in the transaction so that
the skip occurs on other root level bean traversals (the delete of the
2nd master bean)
2019-04-09 20:30:17 +12:00
rob bygrave 2430404e1f Merge branch 'FOCONIS-bug-delete-with-version' 2019-04-09 20:27:23 +12:00
rob bygrave d433e0ea46 Merge branch 'bug-delete-with-version' of https://github.com/FOCONIS/ebean into FOCONIS-bug-delete-with-version 2019-04-09 20:06:12 +12:00
rob bygrave 42591a5a87 No effective change - reformat line 2019-04-09 20:05:22 +12:00
Roland PramlandRob Bygrave 65a62bf683 Fix check constraint support for MariaDB >= 10.2.1 (#1668)
* fixed the check constraint support for mysql/mariadb

* update migration scripts
2019-04-09 19:38:57 +12:00
Roland Praml 3e3f3c35e7 add test case to show delete with version 2019-04-08 17:21:23 +02:00
Rob BygraveandGitHub f4db7ca0bb Update sponsors in README 2019-04-08 20:49:28 +12:00
rob bygrave b0e487cfbd Add sponsor payintech.com 2019-04-03 23:24:13 +13:00
rob bygrave 23fd29ddf1 #1659 - CVE-2018-12022 - Bump Jackson version from 2.9.5 to 2.9.8 2019-04-01 23:23:02 +13:00
rob bygrave f21cac5d4f [maven-release-plugin] prepare for next development iteration 2019-04-01 23:13:07 +13:00
rob bygrave c2e5619f70 [maven-release-plugin] prepare release ebean-11.36.4 2019-04-01 23:12:53 +13:00
rob bygrave 18e0ff7067 #1665 - Incorrect query execution metrics for ORM query converted to DTO query via asDto() 2019-04-01 23:11:16 +13:00
rob bygrave 4119c02f0d #1663 Additionally trim the OrmQueryDetail.asString() output removing extra whitespace 2019-04-01 23:09:58 +13:00
rob bygrave 8985d37aed Merge branch 'master' of github.com:ebean-orm/ebean 2019-04-01 22:25:24 +13:00
Rob BygraveandGitHub 23e035894f Add foconis.de as sponsor to readme 2019-04-01 22:24:50 +13:00
rob bygrave 32b8fd0e26 #1663 Additionally trim the OrmQueryDetail.asString() output removing extra whitespace 2019-03-29 00:43:32 +13:00
rob bygrave 4971db54c8 #1663 - AutoTune - merge profiling such that "select (orderDate) fetch customer (id)" instead merges to "select (orderDate,customer)" 2019-03-29 00:19:21 +13:00
rob bygrave e417b3cde2 #1661 - AutoTune - callstack filters _ebean_ methods 2019-03-28 20:47:34 +13:00
rob bygrave d23ca31e42 [maven-release-plugin] prepare for next development iteration 2019-03-27 16:44:00 +13:00
rob bygrave c9b71ae373 [maven-release-plugin] prepare release ebean-11.36.3 2019-03-27 16:43:47 +13:00
rob bygrave f06f21cf5e #1660 - Modify MetaOrmQueryMetric getQueryPlanHash to return hash of sql 2019-03-27 16:12:09 +13:00
rob bygrave f8b97ff397 #1658 - ENH: Add label to ProfileLocation and use as default query label
- Extend/propagate the label from the origin query to secondary queries
(appending the relative path).
2019-03-27 12:57:36 +13:00
rob bygrave fc032c632b #1658 - ENH: Add label to ProfileLocation and use as default query label 2019-03-27 09:37:35 +13:00
rob bygrave 54534ea7f3 #1657 - ERROR BeanDescriptorManager - Error in deployment java.lang.RuntimeException: Expecting [ ... ] to start with "select" 2019-03-21 22:30:27 +13:00
rob bygrave 812dcbb4bb #1653 - ENH: Add support for ClickHouse database
With array type conversion for primitive arrays
2019-03-20 23:13:50 +13:00
rob bygrave a3d4b57b94 Merge branch 'feature/1653-clickhouse' 2019-03-20 22:07:42 +13:00
rob bygrave 61479d365a Merge branch 'master' of github.com:ebean-orm/ebean 2019-03-20 22:05:54 +13:00
ooknightandRob Bygrave 3ba9a52b0e add server config : default enum type (#1655)
ENH: add server config : default enum type
2019-03-20 21:45:44 +13:00
rob bygrave 518ba37fb2 No effective change - Bump maven plugin version 2019-03-16 15:28:44 +13:00
rob bygrave fd6a7f64eb [maven-release-plugin] prepare for next development iteration 2019-03-14 21:17:03 +13:00
rob bygrave 8b073ef10a [maven-release-plugin] prepare release ebean-11.36.2 2019-03-14 21:16:47 +13:00
rob bygrave 6a7555055d No effective change - Update tests from Ebean -> DB 2019-03-14 21:11:59 +13:00
rob bygrave eb31f1bfce No effective change - Add more tests for LocalDate pre 1900 etc 2019-03-14 16:20:14 +13:00
rob bygrave 2e4f99318a No effective change - Ebean -> DB in tests 2019-03-14 16:15:47 +13:00
rob bygrave 409c1d06b2 #1652 - Conversion problem between org.joda.time.LocalDate and java.sql.Date field for dates before Jan 2 1900 2019-03-14 16:08:04 +13:00
rob bygrave 01f2881940 #1653 - ENH: Add support for ClickHouse database
With array type conversion etc
2019-03-14 14:44:30 +13:00
rob bygrave aef512a851 #1653 - ENH: Add support for ClickHouse database 2019-03-14 00:08:13 +13:00
rob bygrave 435e1f61fe #1651 - ENH: Support change to io.ebean.Model that supports named databases (other than default database) 2019-03-13 15:05:08 +13:00
rob bygrave 0230e3e253 Reduce logging for CI server 2019-03-12 15:06:26 +13:00
rob bygrave 770364fd1a [maven-release-plugin] prepare for next development iteration 2019-03-12 14:53:24 +13:00
rob bygrave fbc2d70967 [maven-release-plugin] prepare release ebean-11.36.1 2019-03-12 14:53:09 +13:00
rob bygrave 276e865f72 #1647 - Change ServerConfig.updateAllPropertiesInBatch to default to false 2019-03-12 14:49:00 +13:00
rob bygrave 9ded3890d7 #1649 - ENH: Add optional length() attribute to @DbEnumValue 2019-03-12 14:31:44 +13:00
rob bygrave bfeb0cd667 No effective change - update to using "Database" and DB 2019-03-12 14:29:28 +13:00
rob bygrave 119049b696 Javadoc update using "Database" vs "EbeanServer" 2019-03-07 16:53:13 +13:00
rob bygrave 33ff113585 #1648 - Change BeanFinder and BeanRepository to use Database rather than EbeanServer 2019-03-07 16:51:33 +13:00
rob bygrave 17e0953cad Javadoc update - reduce generated packages 2019-03-07 16:26:05 +13:00
rob bygrave e3ca5d2419 Javadoc update using "DB" and hide DB constructor 2019-03-07 12:01:05 +13:00
rob bygrave a5f435dbcf Javadoc update using "DB" 2019-03-07 11:25:34 +13:00
rob bygrave aa1e021501 Javadoc update using "DB" 2019-03-07 11:10:58 +13:00
rob bygrave 7ea6f16207 Javadoc update using "DB" vs "Ebean" 2019-03-07 10:56:56 +13:00
rob bygrave 197852857d #1646 - Ensure that java.sql.Array.free() is called 2019-03-07 09:25:48 +13:00
rob bygrave e7e6e00473 No effective change - Finder javadoc to use "Database" 2019-03-07 09:08:34 +13:00
rob bygrave 933c791d33 No effective change - Finder javadoc to use "Database" 2019-03-06 23:13:24 +13:00
rob bygrave 043c523c2a [maven-release-plugin] prepare for next development iteration 2019-03-05 23:06:29 +13:00
rob bygrave 82247fd4e4 [maven-release-plugin] prepare release ebean-11.35.3 2019-03-05 23:06:14 +13:00
rob bygrave 27f86548a6 #1645 - ENH: Add expression rawOrEmpty() ... as a convenience for conditionally added a raw expression 2019-03-05 23:03:22 +13:00
rob bygrave 7e8424328f [maven-release-plugin] prepare for next development iteration 2019-03-05 22:26:35 +13:00
rob bygrave 923828ce87 [maven-release-plugin] prepare release ebean-11.35.2 2019-03-05 22:26:19 +13:00
rob bygrave e195f20981 #1645 - ENH: Add expression rawOrEmpty() ... as a convenience for conditionally added a raw expression 2019-03-05 22:13:38 +13:00
rob bygrave 86d0216159 #1644 - ENH: Improve batch flush when multiple "top level" (unrelated) types are persisted 2019-03-04 12:42:08 +13:00
rob bygrave a4698ea1b6 #1643 - ENH: Add expression inOrEmpty() ... as a convenience for conditionally added a IN expression 2019-03-01 18:24:00 +13:00
rob bygrave 888384f7db No effective change (change to DB from Ebean for TestSubQuery) 2019-03-01 18:12:36 +13:00
rob bygrave 817c946eeb [maven-release-plugin] prepare for next development iteration 2019-02-24 16:20:36 +13:00
rob bygrave 1749c2cb4c [maven-release-plugin] prepare release ebean-11.35.1 2019-02-24 16:20:21 +13:00
rob bygrave 3afd3c4530 #1640 Additionally add expression eq and in support for Inet and Postgres any
Bump ebean-types to 1.3 with of() helper methods
2019-02-24 16:18:49 +13:00
rob bygrave e5f98f1b7a #1640 Additionally add expression eq and in support for Inet and Postgres any 2019-02-24 15:29:07 +13:00
rob bygrave 2e496c9e1e Bump pom to 11.35.1-SNAPSHOT 2019-02-21 22:15:49 +13:00
Rob BygraveandGitHub 5975694538 #1640 - For Postgres support mapping InetAddress to INET db column (#1641)
* #1640 - For Postgres support mapping InetAddress to INET db column

* #1640 - For Postgres support mapping InetAddress to INET db column

Support for Inet and Cdir types + offlineMigrationGeneration + PlatformConfig.databaseInetAddressVarchar for turning off InetAddress mapping on Postgres
2019-02-21 22:14:21 +13:00
rob bygrave 03a42f7f6e No effective change - update test DefaultProfileHandlerTest to output profiling files to target 2019-02-21 09:37:14 +13:00
rob bygrave 84f1e05eb4 [maven-release-plugin] prepare for next development iteration 2019-02-18 10:58:21 +13:00
rob bygrave da20ced1ed [maven-release-plugin] prepare release ebean-11.34.3 2019-02-18 10:58:08 +13:00
rob bygrave 1f1a6e2c04 #1642 - Bump to ebean-datasource 4.5.1 with offline/online support 2019-02-18 10:50:34 +13:00
Roland PramlandRob Bygrave 6b83800a83 FIX: Proper sort of migration versions (possible regression due #1577) (#1639) 2019-02-17 17:40:07 +13:00
rob bygrave c344551e4d [maven-release-plugin] prepare for next development iteration 2019-02-13 11:57:09 +13:00
rob bygrave 6b4aff7191 [maven-release-plugin] prepare release ebean-11.34.2 2019-02-13 11:56:55 +13:00
Roland PramlandRob Bygrave fc7fae35c9 FIX: When saving multiple m2m beans, only last m2m wins (Regression due #1630) (#1638)
* provide test case, that shows problem on multiple-m2m

* FIX: When saving multiple m2m beans, only last m2m wins (Regression due #1630)
2019-02-12 09:31:04 +13:00
rob bygrave 7929d8c0b8 Fix test data ordering 2019-02-11 23:17:54 +13:00
rob bygrave 058766dd92 No effective change - adjust test to use DB and try with resources 2019-02-11 23:13:57 +13:00
rob bygrave 4fdb8a77b4 Fix test data 2019-02-11 23:08:50 +13:00
Manuel PoloandRob Bygrave 56be1fc047 Fixed missing EBEAN_PROPS_FILE loading (#1635) 2019-02-11 23:02:10 +13:00
rob bygrave 192a946cf6 #1634 ENH: Add convenience expressions "equal to or null" eqOrNull() 2019-02-11 22:59:47 +13:00
rob bygrave aa7b15fd6e #1637 - build on jdk11 2019-02-11 22:48:10 +13:00
Roland PramlandRob Bygrave cb74ef01e0 build on jdk11 (#1637) 2019-02-11 22:42:05 +13:00
rob bygrave 829dfcb013 #1634 - ENH: Add convenience expressions "greater than or null" gtOrNull(), ltOrNull() and inRangeWith() 2019-02-09 00:30:55 +13:00
rob bygrave 25b6d2a5a0 [maven-release-plugin] prepare for next development iteration 2019-02-07 23:43:13 +13:00
rob bygrave 14fbc3a955 [maven-release-plugin] prepare release ebean-11.34.1 2019-02-07 23:42:57 +13:00
rob bygrave e41da2f995 #1632 - ENH: Add bind parameter expansion for SqlUpdate
Fix test with bind type.
2019-02-07 23:35:44 +13:00
rob bygrave ea60e42a4d #1633 - ENH: Add bind parameter expansion for raw() expressions 2019-02-07 23:29:42 +13:00
rob bygrave efce6b57e1 #1632 - ENH: Add bind parameter expansion for SqlUpdate 2019-02-07 23:19:00 +13:00
rob bygrave 988e4c7386 WIP Bind parameter expansion 2019-02-07 21:10:57 +13:00
rob bygrave 9e1d7ab722 #1631 - Change logging for SqlUpdate ... such that it is more consistent with other SQL logging wrt JDBC batch 2019-02-07 17:20:49 +13:00
rob bygrave 0c03a8b925 #1630 - ENH: Improve jdbc batch use when persisting ManyToMany intersection changes 2019-02-05 17:35:58 +13:00
rob bygrave 37a66f1ee2 Playing around with SqlUpdate and bind expansion for ?1 etc 2019-02-04 14:24:47 +13:00
rob bygrave a02673359d No effective change - tidy BindParams 2019-02-04 12:34:02 +13:00
rob bygrave f9d13cbba7 Merge branch 'master' of github.com:ebean-orm/ebean 2019-02-04 11:55:04 +13:00
rob bygrave f787483e30 #1629 - ENH: Add sqlQuery(sql) and sqlUpdate(sql) ... as alias for createSqlQuery(sql) and createSqlUpdate(sql) 2019-02-04 11:54:45 +13:00
rob bygrave 9e33f36808 #1629 - ENH: Add sqlQuery(sql) and sqlUpdate(sql) ... as alias for createSqlQuery(sql) and createSqlUpdate(sql) 2019-02-04 11:14:54 +13:00
Roland PramlandRob Bygrave 6a7e6caa66 Test fixes (#1628)
* FIX: mysql index sizes

* FIX: osolete whitespace in sqlserver tests

* Updated mssql-jdbc, this fixes problems in the batch insert (https://github.com/Microsoft/mssql-jdbc/pull/912)

* fix tablename  (reserved word in mariadb)

* ignored failing tests for sqlserver
2019-02-04 09:20:09 +13:00
rob bygrave 5a4a0e3886 Bump version to 11.34.1-SNAPSHOT 2019-02-03 22:39:23 +13:00
rob bygrave c3f586c461 Merge branch 'feature/1624-Database' 2019-02-03 22:21:36 +13:00
rob bygrave 99f7243d6c #1627 - Bump ebean-datasource to 4.3.4 2019-02-03 22:14:25 +13:00
rob bygrave 7026c00290 [maven-release-plugin] prepare for next development iteration 2019-02-02 22:29:02 +13:00
rob bygrave 448d94a335 [maven-release-plugin] prepare release ebean-11.33.3 2019-02-02 22:28:47 +13:00
rob bygrave 961a7ef7ea #1626 - ENH: Add SqlUpdate.setParams(Object ... ) and SqlQuery.setParams(Object ... ) ... as convenient alternative to many setParameter() calls 2019-02-02 22:17:07 +13:00
rob bygrave 5cef1ad017 #1625 - Populate UUID via database column default value / impossible to disable automatic generation for @Id fields of type UUID. 2019-02-02 20:16:05 +13:00
rob bygrave b814ca6e81 Bump ebean-migration to 11.14.1 with logging improvement 2019-02-02 17:37:21 +13:00
rob bygrave a24e6b6064 #1623 - DbOrderByTrim doesn't remove asc/desc if you're sorting by a function called on a column
This fix removes the word boundary check prior to the blank space for asc and desc (allowing the preceeding char to be a brace or anything)
2019-02-02 00:40:56 +13:00
rob bygrave b751823abb #1624 - ENH: Create io.ebean.DB as alias for Ebean and io.ebean.Database as alias for EbeanServer
Adjust Model and Finder to use DB and Database
2019-02-01 23:20:53 +13:00
rob bygrave f3cb7e2cfd #1624 - ENH: Create io.ebean.DB as alias for Ebean and io.ebean.Database as alias for EbeanServer 2019-02-01 22:53:41 +13:00
rob bygrave 31d7c6fed8 #1622 - ENH: Bump ebean-datasource to 4.3.3 with improved DataSourceInitialiseException 2019-01-30 12:10:16 +13:00
rob bygrave c5fb1dbe23 [maven-release-plugin] prepare for next development iteration 2019-01-29 15:59:24 +13:00
rob bygrave b7770a9617 [maven-release-plugin] prepare release ebean-11.33.2 2019-01-29 15:59:11 +13:00
rob bygrave 41abf34ef6 #1621 - Consider clean up white space in generated SQL (as in remove unneeded extra spaces) 2019-01-25 01:52:23 +13:00
rob bygrave 89beaee0f6 #1621 - Consider clean up white space in generated SQL (as in remove unneeded extra spaces) 2019-01-25 01:47:21 +13:00
rob bygrave 5052afbd07 #1620 - Support case statement in order by clause 2019-01-23 22:28:53 +13:00
rob bygrave d89a58482c no effective change - tidy test order by parse 2019-01-23 21:48:49 +13:00
rob bygrave eb1bca805e #1619 - Support aggregation formula on fetch clause e.g. query.fetch("machineUsage", "sum(totalKms)") 2019-01-23 16:45:47 +13:00
rob bygrave 9cb66b112f [maven-release-plugin] prepare for next development iteration 2019-01-23 00:31:34 +13:00
rob bygrave 210901ee2d [maven-release-plugin] prepare release ebean-11.33.1 2019-01-23 00:31:18 +13:00
rob bygrave 396fb49acd #1618 - ENH: Add @Sum ... as short hand for @Aggregation("sum(<property name>)") 2019-01-23 00:29:51 +13:00
rob bygrave a83896f1ff #1617 - save() on a reference bean causes insert to occur ... results in duplicate key exception
Fix
2019-01-22 21:59:17 +13:00
rob bygrave 3483372ae3 #1617 - save() on a reference bean causes insert to occur ... results in duplicate key exception
Tests broken by fix as the test inserts only included id value in the insert
2019-01-22 21:59:04 +13:00
rob bygrave 4e1f817ade #1617 - save() on a reference bean causes insert to occur ... results in duplicate key exception
Tests that reproduce the issue (supplied by Andre - thanks for that)
2019-01-22 21:54:03 +13:00
rob bygrave d4139aa8ef #1616 - Enhance EQL grammer 1) Allow select without ( and ) 2) support aggregate functions min,max,sum,count,avg 3) support quoting fetch paths (that are keywords)
Fix test for Postgres any()
2019-01-22 21:23:16 +13:00
rob bygrave a6cfed7c44 #1616 - Enhance EQL grammer 1) Allow select without ( and ) 2) support aggregate functions min,max,sum,count,avg 3) support quoting fetch paths (that are keywords) 2019-01-22 21:12:18 +13:00
rob bygrave cc17ea8911 No effective change - improve tests for TestAggregationTopLevel 2019-01-22 20:26:50 +13:00
rob bygrave 141f0a8b16 Testing out concept - aggregation formula on fetch clause 2019-01-22 15:56:20 +13:00
rob bygrave 9dbd903a73 No effective change - Update tests for aggregation queries 2019-01-22 15:53:47 +13:00
rob bygrave b8105190d1 #1615 - findNative() with List/array named parameter throws error ... query plan key doesn't take bind count into account 2019-01-22 01:56:58 +13:00
rob bygrave ef3d911e19 #1614 - Refactor DbMigration.generateMigration() to use System out to log key messages and throw UnknownResourcePathException 2019-01-22 01:08:15 +13:00
rob bygrave 31fd0b7ed5 Bump version to 11.33.1-SNAPSHOT 2019-01-22 01:04:25 +13:00
rob bygrave 26d1288757 #1613 - When using transaction.setPersistCascade(false) ... a Delete query should not cascade 2019-01-22 00:05:19 +13:00
rob bygrave 1d49e5b341 #1613 - When using transaction.setPersistCascade(false) ... a Delete query should not cascade 2019-01-21 22:09:15 +13:00
rob bygrave 4a0806e453 #1612 - query.setMapKey("customer.id") throws NullPointerException (ie. mapKey is a path rather than local property) 2019-01-21 21:57:30 +13:00
rob bygrave ab48f796c6 #1611 - ENH: Add inRange expression (as half open expression) ... (property >= lowerValue and property < upperValue)
Bump antlr4-runtime from 4.7.1 to 4.7.2
2019-01-21 20:30:39 +13:00
rob bygrave 0cb8bb0415 #1611 - ENH: Add inRange expression (as half open expression) ... (property >= lowerValue and property < upperValue)
Add inrange to EQL grammer
2019-01-21 20:28:38 +13:00
rob bygrave 471691c747 #1611 - ENH: Add inRange expression (as half open expression) ... (property >= lowerValue and property < upperValue) 2019-01-21 20:01:57 +13:00
rob bygrave c86e6b3cf9 #1610 - Refactor: Change SQL logging such that jdbc batch use is more obvious 2019-01-21 19:31:28 +13:00
rob bygrave b399713a85 No effective change - update readme 2019-01-17 17:19:35 +13:00
rob bygrave f8d4ad7f33 No effective change - update on Transaction 2019-01-16 15:44:45 +13:00
rob bygrave 7984a9ccd1 No effective change - update test to use try with resources 2019-01-16 11:13:43 +13:00
rob bygrave 27cda09523 Merge branch 'master' of github.com:ebean-orm/ebean 2019-01-15 22:16:15 +13:00
rob bygrave 20fc23c19c No effective change - improve javadoc for ExpressionList 2019-01-15 22:16:03 +13:00
André CamiloandRob Bygrave bac53a5d75 FIX: insert in batch OneToOne relationship (#1609) 2019-01-15 11:56:52 +13:00
rob bygrave 2e0690efa9 No effective change - improve javadoc for Transaction and EbeanServer 2019-01-14 23:10:56 +13:00
rob bygrave fdd9b1905c No effective change - improve javadoc for query.exists() and query.setBaseTable() 2019-01-10 14:52:55 +13:00
rob bygrave fc966618a6 No effective change - improve javadoc for Query.setInheritType() 2019-01-10 14:42:55 +13:00
rob bygrave 669ba7837a [maven-release-plugin] prepare for next development iteration 2019-01-10 03:44:59 +13:00
rob bygrave 0edf90056c [maven-release-plugin] prepare release ebean-11.32.1 2019-01-10 03:44:44 +13:00
Rob BygraveandGitHub 6b27a9d280 Support @ManyToOne inside @Embeddables - fix for #52 (#1608)
* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Initial test and work

* #52 - @ManyToOne support inside @Embeddables

Update test with sql capture

* #52 - @ManyToOne support inside @Embeddables

Update test with cache clearing before hand (such that we hit DB on lazy load)
2019-01-10 03:40:02 +13:00
rob bygrave 2b0669c2ae #1594 - Support loading of beans with invalid JSON content
Adjust to be per query via query.setAllowLoadErrors() rather than a
global config via ServerConfig.
2019-01-09 20:03:26 +13:00
rob bygrave 9fc10e8e04 Merge branch 'FOCONIS-feature/load-error' 2019-01-09 19:26:13 +13:00
rob bygrave fb5eb0cdd2 Merge branch 'feature/load-error' of https://github.com/FOCONIS/ebean into FOCONIS-feature/load-error 2019-01-09 19:25:50 +13:00
rob bygrave 3351882915 #1602 - Adjust test adding sql checking for discriminator 2019-01-09 19:20:05 +13:00
Roland PramlandRob Bygrave 31c6d16e73 A query on inherited beans can be restricted to the subtype of one of its children (#1602)
ENH: A query on inherited beans can be restricted to the subtype of one of its children
2019-01-09 19:15:04 +13:00
rob bygrave cd8c12a9a8 #1566 - ENH: Support query.setBaseTable() ... to query against dynamic table (ala manual table partitioning) 2019-01-09 19:13:35 +13:00
rob bygrave 3207ae1f08 No effective change - tidy test 2019-01-09 19:05:16 +13:00
Roland PramlandRob Bygrave 5fe532c393 Refactor: relpaced system-property "ebean.ignoreExtraDdl" with serverConfig flag (#1597) 2019-01-09 16:17:11 +13:00
rob bygrave 93b9cbf9ac bump to 11.32.1-SNAPSHOT 2019-01-09 14:01:25 +13:00
rob bygrave 8a34d6050b #1607 - ENH: Add query.exists() query ... as a convenience for "does a row exist" check 2019-01-09 13:59:53 +13:00
rob bygrave ab3e6ccbf7 [maven-release-plugin] prepare for next development iteration 2019-01-09 12:43:01 +13:00
rob bygrave cc58fc8195 [maven-release-plugin] prepare release ebean-11.31.3 2019-01-09 12:42:48 +13:00
rob bygrave 1c34c09f3c #1606 - Bean with Inheritance and OneToMany with JoinTable and cascade ... doesn't cascade save on all bean types 2019-01-09 12:37:13 +13:00
rob bygrave 8544712448 #1606 - Bean with Inheritance and OneToMany with JoinTable and cascade ... doesn't cascade save on all bean types 2019-01-09 12:29:28 +13:00
rob bygrave 5e22079366 [maven-release-plugin] prepare for next development iteration 2019-01-08 23:04:14 +13:00
rob bygrave 903b0a3929 [maven-release-plugin] prepare release ebean-11.31.2 2019-01-08 23:03:59 +13:00
Roland PramlandRob Bygrave b18bc82b8a FIX: possible NPE in DeleteUnloadedForeignKeys.deleteCascade and in initPostTarget (#1601) 2019-01-08 22:41:43 +13:00
Roland PramlandRob Bygrave 50de32af29 Fixed tests, if SqlServer has "Latin1_General_100_BIN2" collation. (#1600)
This means, all names are interpreted case sensitive by the db
2019-01-08 22:40:14 +13:00
Roland PramlandRob Bygrave 0b18189e62 exposed the schedule methods in BackgroundExecutor (#1599) 2019-01-08 22:39:08 +13:00
Roland PramlandRob Bygrave 0b6e73d729 FIX: create uuid-state file in user's home directory (#1598) 2019-01-08 22:37:42 +13:00
Roland PramlandRob Bygrave 3108076953 SqlServer queryplan captured in transaction & fix of possible NPE (#1592)
* SqlServer queryplan captured in transaction & fix of possible NPE

* rolled back transaction earlier
2019-01-08 22:15:31 +13:00
Roland PramlandRob Bygrave 7ed4435ccc Fix some testcases fof MySql/SqlServer (#1591)
* FIX testcases for MariaDB+utf8mb4  (Failure was: "Specified key was too long; max key length is 767 bytes")

* Excluded tests that won't work on SqlServers generated ids
2019-01-08 22:13:55 +13:00
rob bygrave 7aef4ff1bd #1605 - RuntimeException: Nothing in batch? ... when lazy loading on partially populated L2 bean cache 2019-01-08 21:44:18 +13:00
rob bygrave 5bcad17ae1 No effective change - add a test for filterMany with isNotEmpty() 2019-01-08 16:50:28 +13:00
rob bygrave b1beb0b787 #1596 - NullPointerException at findOne() with filterMany() 2019-01-07 22:21:54 +13:00
rob bygrave 585eb2b57b #1604 - Open URL resources without caching 2019-01-07 22:10:17 +13:00
rob bygrave 2653ec50aa #1604 - Open URL resources without caching 2019-01-07 21:52:55 +13:00
rob bygrave cb4432a588 No effective change - Bump agent to 11.27.1 2019-01-07 21:46:14 +13:00
Roland Praml 4d93b70bf9 Supports loading of corrupt beans 2019-01-03 11:43:50 +01:00
rob bygrave 0b299edf0d [maven-release-plugin] prepare for next development iteration 2018-12-21 20:56:41 +13:00
rob bygrave cf10246783 [maven-release-plugin] prepare release ebean-11.31.1 2018-12-21 20:56:26 +13:00
rob bygrave babba914a0 No effective change - add toString() for ServerCacheNotification 2018-12-21 17:14:29 +13:00
rob bygrave 0397140e0b #1589 - Refactor internals move SqlQuery sqlDistinct ... to SqlTreeNodeRoot (query plan) 2018-12-21 15:57:07 +13:00
rob bygrave 82def2710e No effective change - adjust test to have at least 1 column on insert 2018-12-21 15:51:09 +13:00
rob bygrave 60ad417e1b No effective change - adjust test to have at least 1 column on insert 2018-12-21 15:21:01 +13:00
rob bygrave 3af1b574fd #1588 -Fix query plan capture excluding update and delete queries from query plan capture 2018-12-21 14:31:49 +13:00
rob bygrave 60c8683914 No effective change - test assert to contains rather than containsExactly 2018-12-21 14:29:50 +13:00
rob bygrave 72263c0af0 No effective change - test assert to contains rather than containsExactly 2018-12-21 13:57:00 +13:00
rob bygrave f66316138d #1584 - Fix for - Query cache bug, which produces wrong results 2018-12-21 13:53:05 +13:00
Roland PramlandRob Bygrave b403942491 Query cache bug, which produces wrong results (#1584) 2018-12-21 11:55:07 +13:00
rob bygrave baa3909c63 #1586 - ENH: Add TimedMetric.addSinceNanos() ... as a helper when using start nanos 2018-12-21 02:28:23 +13:00
rob bygrave 81f42f8e95 #1587 - Fix for propagation of @Cache(nearCache=true) 2018-12-21 02:19:21 +13:00
rob bygrave 0377e3ec5c #1586 - ENH: Add TimedMetric.addSinceNanos() ... as a helper when using start nanos 2018-12-21 02:10:16 +13:00
rob bygrave 58f6c67d78 #1585 - Change the L2 bean cache keys to be String based 2018-12-21 01:54:46 +13:00
rob bygrave 84f7fc5d81 No effective change - javadoc for ServerConfig getServiceObject 2018-12-19 21:20:37 +13:00
rob bygrave ea02bebc6f [maven-release-plugin] prepare for next development iteration 2018-12-19 21:16:42 +13:00
rob bygrave da874d84a8 [maven-release-plugin] prepare release ebean-11.30.1 2018-12-19 21:16:27 +13:00
rob bygrave 049cacad1c #1583 - ENH: Add type safe ServerConfig getServiceObject(Class<P> cls) and putServiceObject() 2018-12-19 21:14:25 +13:00
rob bygrave ced8c79458 #1582 - ENH: Pass @Cache nearCache option to ServerCacheOptions (for L2 plugins like Redis) 2018-12-19 20:57:45 +13:00
rob bygrave a66edf8077 #1477 Query plan capture - use explain analyze for Postgres
... so that we also get DB side timing
2018-12-19 16:55:24 +13:00
Rob BygraveandGitHub 94591954b3 1476 - Query plan capture, initial wip capturing bind params (#1477)
* 1476 - Query plan capture, initial wip capturing bind params

* No effective change - Reset test default db to H2

* #1476 - Query plan capture, initial wip capturing bind params #1477

Update with consumer

* #1476 - Query plan capture, initial wip capturing bind params #1477

Update with query plan request

* #1476 - Query plan capture, initial wip capturing bind params #1477

Extract interface

* #1476 - Query plan capture, initial wip capturing bind params #1477

Extract interface
2018-12-19 16:04:28 +13:00
rob bygrave e611353163 No effective change - update javadoc for QueryIterator to use try with resources 2018-12-19 15:22:32 +13:00
rob bygrave e7811910e9 No effective change - update javadoc 2018-12-19 15:15:38 +13:00
rob bygrave 138b587ff7 #1581 - ENH: Add query.asUpdate() ... to convert a query into an UpdateQuery (typically with query beans) 2018-12-19 14:45:33 +13:00
rob bygrave 8fc6c4c648 #1580 - Refactor move io.ebeaninternal.metric to public package of io.ebean.metric (such that it can be used by plugins like redis l2 cache plugin) 2018-12-19 14:16:36 +13:00
rob bygrave ebdc28e1cd #1579 - ENH: for UpdateQuery add setLabel() and update() as top level methods 2018-12-19 13:58:28 +13:00
rob bygrave 51f79e769c [maven-release-plugin] prepare for next development iteration 2018-12-17 23:39:34 +13:00
rob bygrave c2a69714ca [maven-release-plugin] prepare release ebean-11.29.1 2018-12-17 23:39:18 +13:00
rob bygrave f3213e7b90 Bump to 11.29.1-SNAPSHOT 2018-12-17 23:19:43 +13:00
rob bygrave 55de997297 #1578 - Remove unmaintained META-INF/ebean-version.mf manifest file ... use EbeanVersion.getVersion() instead 2018-12-17 23:18:29 +13:00
rob bygrave 65890f9777 No effective change - remove unused resources from test resources 2018-12-17 23:14:51 +13:00
rob bygrave 41c1e7260c #1577 - ENH: Add support for "dbinit" migrations (Sort of "checkpoint" or "fast forward" migrations) 2018-12-17 23:11:13 +13:00
rob bygrave 7d35789db4 #1573 - Incorrect CamelCase conversion when number proceeds uppercase letter 2018-12-16 16:12:34 +13:00
rob bygrave d266d6d440 #1574 - "NullPointerException" in query.copy().findList() but not in query.findList() 2018-12-16 00:29:18 +13:00
rob bygrave 6d5374e66a #1576 - ClusterManager creates ClusterBroadcast even when config is not active 2018-12-15 23:17:00 +13:00
rob bygrave 8410de8831 #1573 - Incorrect CamelCase conversion when number proceeds uppercase letter 2018-12-13 00:19:40 +13:00
rob bygrave 4b0230e862 Refactor - reduce visibility on DefaultDbMigration 2018-12-11 21:03:45 +13:00
rob bygrave fa96f81f8c [maven-release-plugin] prepare for next development iteration 2018-12-06 00:19:14 +13:00
rob bygrave a5fea5e9be [maven-release-plugin] prepare release ebean-11.28.3 2018-12-06 00:18:53 +13:00
rob bygrave bafba0babf #1572 - Support query.select("customer.id").findSingleAttributeList() ... in addition to the expected and working select("customer").findSingleAttributeList() 2018-12-06 00:15:06 +13:00
rob bygrave e4088c5fbe #1571 - NPE in cacheable bean with embeddedid on delete 2018-12-05 23:03:15 +13:00
RienandRob Bygrave 0405ceb96c NPE in cacheable bean with embeddedid on delete (#1570) 2018-12-05 21:49:27 +13:00
rob bygrave ebf96c87bf [maven-release-plugin] prepare for next development iteration 2018-12-03 22:14:59 +13:00
rob bygrave fcaf11f262 [maven-release-plugin] prepare release ebean-11.28.2 2018-12-03 22:14:46 +13:00
rob bygrave 05df47c0d7 #1569 - Ebean generates wrong ddl (datetime(6) vs timestamp) for H2 with @History annotation 2018-12-03 22:11:47 +13:00
rob bygrave a8892292fb #1569 - Ebean generates wrong ddl (datetime(6) vs timestamp) for H2 with @History annotation 2018-12-03 22:05:18 +13:00
rob bygrave e876ef8d87 #1559 - @Lob with @ElementCollection 2018-12-03 21:07:33 +13:00
rob bygrave 315b39813b #1568 - @OneToMany with orphanRemoval=true ... with @Cache (and not a @ManyToOne) doesn't remove orphans after cache hit 2018-11-30 23:46:11 +13:00
rob bygrave 6d5e0c4766 Add test only - Add test for L2 cache with orphanRemoval 2018-11-30 23:41:23 +13:00
rob bygrave a2ce17aec0 Add test only - Add test for L2 cache with orphanRemoval 2018-11-30 22:42:36 +13:00
rob bygrave fcffa92c55 #1567 - SqlUpdate addBatch() ... with named parameters errors with PersistenceException: No batched statement found for key 2018-11-30 21:47:23 +13:00
rob bygrave 7fda8079c2 [maven-release-plugin] prepare for next development iteration 2018-11-30 09:55:20 +13:00
rob bygrave cca9bb4427 [maven-release-plugin] prepare release ebean-11.28.1 2018-11-30 09:55:06 +13:00
rob bygrave f45089240a #1565 - Bump to ebean-datasource 4.3.1 ... with option for owner database credentials and InitDatabase 2018-11-30 09:44:07 +13:00
rob bygrave 8252a51545 #1565 - Bump to ebean-datasource 4.3.1 ... with option for owner database credentials and InitDatabase 2018-11-29 10:16:48 +13:00
rob bygrave c440c768cf #1564 - Remove deprecated io.ebeaninternal.server.core.ServletContextListener - migrate to io.ebean.event.ServletContextListener 2018-11-29 10:01:56 +13:00
rob bygrave c6ae501354 #1563 - Remove deprecated noop method ServerConfig.loadTestProperties() - migrate to loadProperties() 2018-11-29 09:59:16 +13:00
rob bygrave 70e2b1c2ae #1562 - Query cache use incorrect with RawExpression - incorrect bind hash 2018-11-29 09:54:24 +13:00
rob bygrave 211f28eea3 [maven-release-plugin] prepare for next development iteration 2018-11-27 14:58:40 +13:00
rob bygrave 174fe46485 [maven-release-plugin] prepare release ebean-11.27.1 2018-11-27 14:58:26 +13:00
rob bygrave 890cc6f66d Bump to 11.27.1-SNAPSHOT 2018-11-27 14:53:06 +13:00
rob bygrave 2f0e5e6e46 #1561 - ENH: Add ScriptRunner API ... for easier running of SQL and DDL scripts (for testing usually) 2018-11-27 14:50:48 +13:00
rob bygrave 54ba78218b #1558 - Bump ebean-migration to 11.11.1 - refer: https://github.com/ebean-orm/ebean-migration/pull/56 2018-11-23 14:36:41 +13:00
rob bygrave ba16cea405 #1556 - Query.setDisableLazyLoading(true) not working on @OneToMany Set (but does on List) 2018-11-23 12:20:18 +13:00
rob bygrave e81a61378c No effective change - javadoc 2018-11-23 11:37:38 +13:00
rob bygrave b4154031cc #1555 - Support .yaml extension (in addition to the existing .yml extension) for application.yaml and application-test.yaml 2018-11-20 11:51:27 +13:00
rob bygrave ecf5b56652 #1555 - Support .yaml extension (in addition to the existing .yml extension) for application.yaml and application-test.yaml 2018-11-20 11:45:45 +13:00
rob bygrave 426c6c8111 #1554 - Improve exception message for BeanNotEnhancedException 2018-11-20 11:33:16 +13:00
rob bygrave 9dbb69f4f4 #1553 - Remove deprecated method Query.setForUpdate(boolean) ... migrate to setForUpdate() 2018-11-19 23:40:00 +13:00
rob bygrave 83776a1eae #1552 - Remove deprecated methods on Transaction setBatch(PersistBatch) .. migrate to setBatchMode(boolean) 2018-11-19 23:36:15 +13:00
rob bygrave 6bc72ae6bb No effective change - format only 2018-11-19 22:25:01 +13:00
Roland PramlandRob Bygrave 4fe2016891 new comparison method Ine (caseInsensitive notEquals) (#1551) 2018-11-19 22:22:46 +13:00
Roland PramlandRob Bygrave 7be4675d3e NEW: ExpressionPath provides access to property and elName (#1550) 2018-11-19 22:16:01 +13:00
rob bygrave 06b71781f5 #1548 add global configuration disableLazyLoading
Add javadoc
2018-11-19 22:08:50 +13:00
rob bygrave 55e4c7bc26 #1548 add global configuration disableLazyLoading
Fix tests
2018-11-19 22:03:51 +13:00
ooknightandRob Bygrave b3584a81b4 add global configuration disableLazyLoading (#1548) 2018-11-19 21:45:05 +13:00
rob bygrave 68da8944ed [maven-release-plugin] prepare for next development iteration 2018-11-14 09:34:02 +13:00
rob bygrave 903ee35d63 [maven-release-plugin] prepare release ebean-11.26.1 2018-11-14 09:33:50 +13:00
rob bygrave 658ee3d39f Bump to 11.26.1-SNAPSHOT 2018-11-14 09:32:25 +13:00
rob bygrave c074b7c457 #1547 - Revert for - FIX for the limit query #1540 2018-11-14 09:29:36 +13:00
rob bygrave 528ad7c7fb [maven-release-plugin] prepare for next development iteration 2018-11-13 23:58:37 +13:00
rob bygrave c3f41f4157 [maven-release-plugin] prepare release ebean-11.25.1 2018-11-13 23:58:22 +13:00
rob bygrave 33d104e6aa Bump version to 11.25.1-SNAPSHOT 2018-11-13 23:52:35 +13:00
rob bygrave 4bd3a0f293 #1546 - Refactor: Swap from entityBean._ebean_intercept() to entityBean._ebean_getIntercept() 2018-11-13 23:50:13 +13:00
rob bygrave 54a4fd75f1 #1539 - FIX: Pairs must not be modified by query
Remove the (|| multiValueSupported) part
2018-11-13 23:44:16 +13:00
Roland PramlandRob Bygrave 105f08cca1 FIX: Pairs must not be modified by query (#1539)
* FIX: Pairs must not be modified by query

* Modification can also occur on inValues.

* fixed tests

* removed obsolete line
2018-11-13 23:41:36 +13:00
rob bygrave 01d9dd3fe8 #1533 - Enhanced bean can not use final fields in Java 9+. 2018-11-13 23:37:45 +13:00
rob bygrave f09b38c58c #1545 - Bump ebean-datasource to 4.2.2 fix for leak with SQLWarning and Postgres JDBC driver 2018-11-13 21:33:44 +13:00
rob bygrave cb6d2e7ec0 Merge branch 'master' of github.com:ebean-orm/ebean 2018-11-13 21:27:13 +13:00
rob bygrave 89c0324e42 #1544 - No effective change - use https://ebean.io for urls 2018-11-13 21:26:56 +13:00
Roland PramlandRob Bygrave 7b4215f4f8 Fix test data (#1541)
* FIX: Put correct dataType for anniversary

* NEW: Add some deterministic ship dates to reference data
2018-11-13 21:09:53 +13:00
Roland PramlandRob Bygrave e4cb5f0443 FIX for the limit query (#1540) 2018-11-13 21:08:53 +13:00
Roland PramlandRob Bygrave ec24374d72 Add some sanity checks when creating sort comparators (#1538) 2018-11-13 20:55:09 +13:00
Roland PramlandRob Bygrave cfba4d2deb Add Java 8 Time API support for BasicTypeConverter (#1537) 2018-11-13 20:53:38 +13:00
rob bygrave 0ab019ca2c Merge branch 'FOCONIS-extrawhere-on-join' 2018-11-13 20:51:55 +13:00
rob bygrave 8c9dae0f88 Merge branch 'extrawhere-on-join' of https://github.com/FOCONIS/ebean into FOCONIS-extrawhere-on-join 2018-11-13 20:51:29 +13:00
Roland PramlandRob Bygrave 88a0c34d37 FIX: use outer join on "is null" check (#1535) 2018-11-13 20:46:18 +13:00
Roland PramlandRob Bygrave ce403e72a7 FIX: improved support for @DbForeignKey(noConstraint = true) (#1527)
* FIX: improved support for DbForeignKey(noConstraint = true)

* FIX: Tests for mariadb and sqlserver

* FIX: SqlServer was still incorrect

* FIX: not ommit property for formula

* Update BeanDescriptor.java (typo fix)

fix typo column (no code change!)
2018-11-13 20:44:45 +13:00
rob bygrave 3c6a52da31 #1531 - Transform extra-ddl.xml files when running in ddl mode (no migration)
Update to ebean-migration to with ScriptTransform as public and reuse here in Ebean
2018-11-13 20:39:15 +13:00
Manuel DanischandRob Bygrave 2806972032 Transform extra-ddl.xml files when running in ddl mode (no migration) (#1531) 2018-11-13 20:20:01 +13:00
rob bygrave acd6ba0a42 Merge branch 'master' of github.com:ebean-orm/ebean 2018-11-13 17:52:09 +13:00
rob bygrave b386c9a5a8 #1543 - ENH: Allow ebean.dbSchema to have multiple schemas 2018-11-13 17:51:57 +13:00
Roland Praml c5536aaeec FIX: append extraWhere to join 2018-11-10 23:42:02 +01:00
Roland Praml 1b2bfc5df8 FIX: use outer join on "is null" check 2018-11-10 23:32:24 +01:00
Roland PramlandRob Bygrave 808004165c Code cleanup (#1534)
* removed unused imports (no code change)

* Add missing @Override / @SupressWarnings (no code change)

* FIX: serialization warnings

* FIX: Access to static member
2018-11-10 20:07:01 +13:00
Roland PramlandRob Bygrave 61eedb4e9a Fixed tests that modify BasicData (#1530) 2018-11-03 16:38:26 +13:00
Roland PramlandRob Bygrave 662ffdd070 FIX: update extra ddl also, if no migration was written (#1529) 2018-11-03 16:26:21 +13:00
Roland PramlandRob Bygrave 13a5511318 FIX: disableLazyLoading was not checked correctly (#1528) 2018-11-03 16:23:27 +13:00
Roland PramlandRob Bygrave 0f9c98964e FIX Typos (DLL -> DDL) (#1526) 2018-11-02 09:21:31 +13:00
rob bygrave b87e6d90f6 [maven-release-plugin] prepare for next development iteration 2018-11-01 17:22:36 +13:00
rob bygrave 166906a814 [maven-release-plugin] prepare release ebean-11.24.1 2018-11-01 17:22:22 +13:00
rob bygrave 1733d2382c Bump agent to 11.24.1 2018-11-01 17:20:41 +13:00
rob bygrave a6f9120905 #1525 - Check for presence of JAXB in classpath in CurrentModel (to support Java 11 without xml) 2018-11-01 13:31:08 +13:00
rob bygrave 32b599512b #1524 - @History on @OneToMany with asOf() query and fetch(many property) gives PersistenceException: Error with property[6] dt[93]data[2018-11-01 14:56:18.015][java.sql.Timestamp] 2018-11-01 00:48:46 +13:00
rob bygrave 34fd24d620 No effective change - add back SQL logging 2018-11-01 00:48:02 +13:00
Rob BygraveandGitHub f928923b5b #1519 - Memory leak when using @Cache(enableQueryCache=true) (#1523)
* #1519 - Memory leak when using @Cache(enableQueryCache=true)

* #1519 - Memory leak when using @Cache(enableQueryCache=true)

Remove unused TransactionEventBeans
2018-10-31 23:53:16 +13:00
rob bygrave 1f928e65a4 #1521 - Add API for using explicit transaction for UpdateQuery - e.g. ebeanServer.update(Customer.class)...update(activeTransaction); 2018-10-30 13:39:54 +13:00
rob bygrave d920d8eb76 #1522 - Refactor - Change io.ebean.Model to not be a annotated with @MappedSuperclass 2018-10-30 13:38:57 +13:00
Michael BenzandRob Bygrave 23d2c64046 JavaDoc Fix closing h3 tag in Transaction. no code change! (#1520) 2018-10-30 12:55:58 +13:00
rob bygrave 19d29cd836 #1514 - Add support for JacksonAnnotations at bean-properties
Fix where Jackson is not present on the classpath
2018-10-26 14:50:17 +13:00
rob bygrave f14c3e8cb4 Merge branch 'master' of github.com:ebean-orm/ebean 2018-10-26 01:34:36 +13:00
rob bygrave b9ca8be95a #1517 - Update for ebean-datasource maven groupId change to io.ebean 2018-10-26 01:34:16 +13:00
rob bygrave d627bb47e2 #1516 - More user friendly exceptions - BeanNotEnhancedException, BeanNotRegisteredException 2018-10-26 01:33:24 +13:00
rob bygrave d395c666fc #1516 - More user friendly exceptions - BeanNotEnhancedException, BeanNotRegisteredException 2018-10-26 01:32:22 +13:00
Roland PramlandRob Bygrave 939397acfc Add support for JacksonAnnotations at bean-properties (#1514) 2018-10-25 22:11:36 +13:00
Roland PramlandRob Bygrave fecb5fa731 There should be only one "Rob" in o_customer (#1515)
* FIX: CsvReader-Test

* Fixes for tests

* reversed changes

* tidy TestCsvReaderWithCallback
2018-10-25 10:35:02 +13:00
rob bygrave bdc9917811 [maven-release-plugin] prepare for next development iteration 2018-10-24 23:51:00 +13:00
rob bygrave afcd6859e0 [maven-release-plugin] prepare release ebean-11.23.1 2018-10-24 23:50:44 +13:00
rob bygrave fef87323b3 Bump to 11.23.1-SNAPSHOT 2018-10-24 23:49:26 +13:00
Rob BygraveandGitHub 6909b20a9e #1510 - Tidy DbMigrationConfig removing the properties that should only be with DbMigration generation (#1513) 2018-10-24 23:31:07 +13:00
rob bygrave c1a479e1f4 #1512 - Invalid SQL with Postgres + order by nulls first/last + where() expression on ManyToMany 2018-10-24 23:26:19 +13:00
rob bygrave e06967ff4a #1512 - Invalid SQL with Postgres + order by nulls first/last + where() expression on ManyToMany 2018-10-24 23:25:48 +13:00
rob bygrave 156469ae0f Update tests for running MySql 2018-10-24 22:59:48 +13:00
rob bygrave 1d1d479dda Fix concat_expectString test with explicit cast to string 2018-10-24 22:17:44 +13:00
rob bygrave d185ea5962 Updated db migration test for mysql 2018-10-24 22:12:42 +13:00
rob bygrave 2dbb5ea80d #1511 - Add SAP HANA support - format only changes 2018-10-24 21:49:48 +13:00
Jonathan BreglerandRob Bygrave 158ee9a081 Add SAP HANA support (#1511) 2018-10-24 21:38:17 +13:00
rob bygrave b1410cc660 [maven-release-plugin] prepare for next development iteration 2018-10-19 20:07:32 +13:00
rob bygrave 4c2e9ccacd [maven-release-plugin] prepare release ebean-11.22.10 2018-10-19 20:07:16 +13:00
rob bygrave 29aa395cd4 #1509 - DBMigration add ... List<String> getPendingDrops(); 2018-10-19 16:24:06 +13:00
rob bygrave 8160d1f01c #1508 - Invalid SQL used to fetch identity value for @Draftable with database platform that uses Identity but not getGeneratedKeys 2018-10-19 15:56:39 +13:00
rob bygrave 6fd76ff697 [maven-release-plugin] prepare for next development iteration 2018-10-15 22:35:28 +13:00
rob bygrave 249cc5df49 [maven-release-plugin] prepare release ebean-11.22.9 2018-10-15 22:35:12 +13:00
rob bygrave 2646e8c27f #1507 - SqlUpdate.execute PersistenceException is not translated into more specific exception (like DuplicateKeyException)
Support for sqlUpdate.executeBatch()
2018-10-15 22:30:42 +13:00
rob bygrave 3eaf47fd70 No effective change - add additional tests 2018-10-15 22:25:38 +13:00
rob bygrave 9d64352771 No effective change - add additional tests 2018-10-15 22:13:18 +13:00
rob bygrave aa7325b249 #1507 - SqlUpdate.execute PersistenceException is not translated into more specific exception (like DuplicateKeyException) 2018-10-15 22:12:39 +13:00
rob bygrave 2839434773 #1506 - @ElementCollection DDL generates 2 indexes on the same column 2018-10-13 00:23:44 +13:00
rob bygrave de9823b69b #1505 - Unidirectional @OneToOne orphanRemoval=true ... does not delete orphan that is replaced 2018-10-12 22:30:06 +13:00
rob bygrave 15cab24848 #1504 - ENH: Add SqlUpdate executeNow() method ... that executes now regardless of transaction batch mode
Add test for UpdateQuery (which executes immediately regardless)
2018-10-12 20:33:59 +13:00
rob bygrave b87e360ac7 #1504 - ENH: Add SqlUpdate executeNow() method ... that executes now regardless of transaction batch mode 2018-10-12 18:49:20 +13:00
rob bygrave 82e68d7756 [maven-release-plugin] prepare for next development iteration 2018-10-05 13:04:31 +13:00
rob bygrave 0371043914 [maven-release-plugin] prepare release ebean-11.22.8 2018-10-05 13:04:15 +13:00
rob bygrave 54b5684628 #1502 - findNative build query to findPagedList, the query count is incorrect. 2018-10-05 12:22:25 +13:00
rob bygrave da95ec0c05 #1501 - Change logging for io.ebeaninternal.dbmigration.DefaultDbMigration to "io.ebean.GenerateMigration" 2018-10-05 11:26:42 +13:00
rob bygrave b5eec93995 #1500 - Improve Postgres 10 partitioning support, easier to create multiple indexes on each partition 2018-10-05 10:41:40 +13:00
rob bygrave fc26765a7e #1499 - findNative with findIds (or findSingleAttributeList with id property) throws ArrayIndexOutOfBoundsException 2018-10-04 22:51:51 +13:00
rob bygrave 9a6d339449 [maven-release-plugin] prepare for next development iteration 2018-10-04 22:10:24 +13:00
rob bygrave 5b09443cdf [maven-release-plugin] prepare release ebean-11.22.7 2018-10-04 22:10:06 +13:00
rob bygrave 31093babe3 #1498 - findIds() with @SoftDelete bean returns all Ids (when soft deleted ones should not return)
And fix delete permanent that cascades
2018-10-04 20:49:30 +13:00
rob bygrave f8b9ca2034 #1498 - findIds() with @SoftDelete bean returns all Ids (when soft deleted ones should not return) 2018-10-04 20:26:00 +13:00
rob bygrave c27749ae2d #1497 - SQL Error with @History + @SoftDelete + @OneToOne fetch=FetchType.EAGER 2018-10-04 19:59:36 +13:00
rob bygrave 2c04430185 No effective change - add testSoftDelete_includeSoftDeletes_findOne 2018-10-04 17:14:53 +13:00
rob bygrave dcde47daf6 Merge branch 'master' of github.com:ebean-orm/ebean 2018-09-28 16:34:08 +12:00
rob bygrave 57056d7abd #1496 - Query label lost for findId() 2018-09-28 16:33:54 +12:00
Rob Bygrave 3409f264ec [maven-release-plugin] prepare for next development iteration 2018-09-26 23:38:57 +12:00
Rob Bygrave 6a61614430 [maven-release-plugin] prepare release ebean-11.22.6 2018-09-26 23:38:42 +12:00
Rob Bygrave 9734ae5787 #1490 - FIX: withQuote_when_match for different platforms 2018-09-26 21:33:27 +12:00
Roland PramlandRob Bygrave b817d5ee4d FIX: withQuote_when:_match for different platforms (#1490) 2018-09-26 21:26:29 +12:00
Rob Bygrave 0036473971 #1489 - removed the concat-operator "||" and replaced with "concat()" 2018-09-26 21:23:14 +12:00
Roland PramlandRob Bygrave a020bb15a1 removed the concat-operator "||" and replaced with "concat()" (#1489)
* removed the concat-operator "||" and replaced with "concat()"

* using || in postgres

* FIX: Assert-statement
2018-09-26 21:19:28 +12:00
Rob Bygrave efa86043bf #1492 - Update for NEW: collation support for orderBy 2018-09-26 21:15:41 +12:00
Roland PramlandRob Bygrave eb1ea5ddd2 NEW: collation support for orderBy (#1492) 2018-09-26 20:57:33 +12:00
Roland PramlandRob Bygrave a83a4fa1c4 FIX: check platform on multiple annotations like '@Formula(platform=...)' (#1495) 2018-09-26 20:55:39 +12:00
Roland PramlandRob Bygrave fe71c7cc4e FIX: tableName detection for native statements on SQLServer (#1494) 2018-09-26 20:54:22 +12:00
Roland PramlandRob Bygrave 5522d56e8d ignored tests for sqlserver, because there is no nested transaction support, yet (#1493) 2018-09-26 20:48:49 +12:00
Roland PramlandRob Bygrave 7e995efb62 Add methods th the plugin API to access type and inheritance information (#1491) 2018-09-26 20:48:19 +12:00
Roland PramlandRob Bygrave ef46bc86cc Original Value and bean change was not computed correctly in changelog (#1488)
* Bug in Changelog: It takes the first non null value as oldValue and does not detect if oldValue == newValue

* CHANGE: EntityBeanIntercept uses bitflags instead of separate boolean arrays - new flag 'origValueSet' introduced - getDirtyValues checks, if values are really different.
2018-09-26 20:40:56 +12:00
rob bygrave 0e75c50be5 #1487 - @OneToOne Postgres with different Id types - error PSQLException: ERROR: operator does not exist: uuid = character varying
Fix
2018-09-24 22:30:45 +12:00
rob bygrave cd1cdb027f #1487 - @OneToOne Postgres with different Id types - error PSQLException: ERROR: operator does not exist: uuid = character varying
Test
2018-09-24 22:30:28 +12:00
Roland PramlandRob Bygrave 66703a3a29 FIX: recursive BatchedPstmtHolder.flush, when BeanPersistController or ChangeLogFilter hit the database (#1486) 2018-09-21 15:38:21 +12:00
Roland PramlandRob Bygrave 56e65d7463 Fix issue in UUID-v1 generator on AWS Beanstalk (#1485) 2018-09-21 15:35:53 +12:00
Roland PramlandRob Bygrave eb7277aa13 Wrong behaviour in BeanMap.put/putAll (#1484) 2018-09-21 15:35:01 +12:00
Rob Bygrave 42f9e74d91 #1483 - Invalid SQL with allQuotedIdentifiers true - where t0.[t0.[COND]] in (?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 2018-09-20 23:12:26 +12:00
Rob Bygrave be24e11b91 [maven-release-plugin] prepare for next development iteration 2018-09-20 21:35:24 +12:00
769 changed files with 27613 additions and 10148 deletions
+28 -3
View File
@@ -1,8 +1,34 @@
[![Build Status](https://travis-ci.org/ebean-orm/ebean.svg?branch=master)](https://travis-ci.org/ebean-orm/ebean)
[![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)
# Sponsors
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://www.foconis.de/" target="_blank">
<img width="222px" src="https://www.foconis.de/templates/yootheme/cache/foconis_logo_322-709da1de.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.payintech.com/" target="_blank">
<img width="222px" src="https://www.payintech.com/wp-content/uploads/2015/10/PayinTech-logo-noir.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://www.premium-minds.com" target="_blank">
<img width="222px" src="https://ebean.io/images/logo-premium-minds.png">
</a>
</td>
</tr>
</tbody>
</table>
# Need help?
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
# Documentation
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
## Maven cental links:
@@ -10,8 +36,7 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
## Current versions
* [![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) - ebean
## Other versions
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
+15
View File
@@ -151,3 +151,18 @@ In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
TODO: not yet tested
'hana' platform
--------------------
Requires an installed SAP HANA server - e.g. https://store.docker.com/images/sap-hana-express-edition
- Create a user `EBEAN_TEST` with password `Eb3an_test` in the tenant database `HXE`
- Adjust the connection string and/or username in `ebean.properties`
run: `mvn clean test -Ddatasource.default=hana`
Current status: PASS
Tests run: 2486, Failures: 0, Errors: 0, Skipped: 84
+46 -17
View File
@@ -9,20 +9,20 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.22.5</version>
<version>11.37.1</version>
<packaging>jar</packaging>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<jackson-core.version>2.9.5</jackson-core.version>
<jackson-core.version>2.9.8</jackson-core.version>
<snakeyaml.version>1.21</snakeyaml.version>
</properties>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.22.5</tag>
<tag>ebean-11.37.1</tag>
</scm>
<profiles>
@@ -111,19 +111,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>2.2.1</version>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>4.2</version>
<version>4.7</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource</artifactId>
<version>3.2.2</version>
<groupId>io.ebean</groupId>
<artifactId>ebean-types</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
@@ -135,13 +141,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>11.9.1</version>
<version>11.14.1</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.7.1</version>
<version>4.7.2</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
@@ -188,6 +194,21 @@
<scope>provided</scope>
</dependency>
<!-- Provided scope to compile with java 11 -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.4.0-b180830.0438</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
<scope>provided</scope>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
<dependency>
<groupId>org.postgresql</groupId>
@@ -222,14 +243,14 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-agentloader</artifactId>
<version>2.1.2</version>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>11.11.1</version>
<version>11.37.1</version>
<scope>test</scope>
</dependency>
@@ -238,7 +259,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<version>1.4.197</version>
<scope>provided</scope>
</dependency>
@@ -259,7 +280,7 @@
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.4.0.jre8</version>
<version>7.2.0.jre8</version>
<scope>test</scope>
</dependency>
@@ -271,6 +292,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sap.cloud.db.jdbc</groupId>
<artifactId>ngdbc</artifactId>
<version>2.3.48</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>avaje-composite-testing</artifactId>
@@ -302,7 +330,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>11.11.1</version>
<version>11.37.1</version>
<executions>
<execution>
<id>test</id>
@@ -320,9 +348,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<version>2.22.1</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<trimStackTrace>false</trimStackTrace>
<failIfNoTests>false</failIfNoTests>
<includes>
<include>**/Test*.java</include>
@@ -364,7 +393,7 @@
<overview>src/main/java/io/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform*</excludePackageNames>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
@@ -1,6 +1,8 @@
package io.ebean;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
@@ -37,4 +39,21 @@ public interface BackgroundExecutor {
* </p>
*/
void executePeriodically(Runnable r, long delay, TimeUnit unit);
/**
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture representing pending completion of the task and
* whose get() method will return null upon completion
*/
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
/**
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture that can be used to extract result or cancel
*/
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
}
+16 -21
View File
@@ -15,8 +15,8 @@ import java.util.Optional;
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
* public CustomerFinder(EbeanServer server) {
* super(Customer.class, server);
* public CustomerFinder(Database database) {
* super(Customer.class, database);
* }
*
* // ... add customer specific finders
@@ -29,25 +29,25 @@ import java.util.Optional;
*/
public abstract class BeanFinder<I,T> {
protected final EbeanServer server;
protected final Database server;
protected final Class<T> type;
/**
* Create with the given bean type and EbeanServer instance.
* Create with the given bean type and Database instance.
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
* @param server The Database instance typically created via Spring factory or equivalent.
*/
protected BeanFinder(Class<T> type, EbeanServer server) {
protected BeanFinder(Class<T> type, Database server) {
this.type = type;
this.server = server;
}
/**
* Return the EbeanServer to use.
* Return the Database to use.
*/
public EbeanServer db() {
public Database db() {
return server;
}
@@ -66,21 +66,20 @@ public abstract class BeanFinder<I,T> {
}
/**
* Return typically a different EbeanServer to the default.
* Return typically a different Database to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
* This is equivalent to {@link DB#byName(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
* @param server The name of the Database. If this is null then the default Database is returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
public Database db(String server) {
return DB.byName(server);
}
/**
* Creates an entity reference for this ID.
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
* Equivalent to {@link Database#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
@@ -89,8 +88,6 @@ public abstract class BeanFinder<I,T> {
/**
* Retrieves an entity by ID.
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T findById(I id) {
@@ -107,8 +104,6 @@ public abstract class BeanFinder<I,T> {
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
@@ -138,7 +133,7 @@ public abstract class BeanFinder<I,T> {
* }</pre>
*
* <p>
* Equivalent to {@link EbeanServer#update(Class)}
* Equivalent to {@link Database#update(Class)}
*/
protected UpdateQuery<T> updateQuery() {
return db().update(type);
@@ -147,7 +142,7 @@ public abstract class BeanFinder<I,T> {
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
* Equivalent to {@link Database#find(Class)}
*/
protected Query<T> query() {
return db().find(type);
+14 -14
View File
@@ -13,7 +13,7 @@ import java.util.Collection;
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* public CustomerRepository(Database server) {
* super(Customer.class, server);
* }
*
@@ -34,23 +34,23 @@ import java.util.Collection;
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Create with the given bean type and EbeanServer instance.
* Create with the given bean type and Database instance.
* <p>
* Typically users would extend BeanRepository rather than BeanFinder.
* </p>
* <pre>{@code
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* public CustomerRepository(Database server) {
* super(Customer.class, server);
* }
*
* }</pre>
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent
* @param server The Database instance typically created via Spring factory or equivalent
*/
protected BeanRepository(Class<T> type, EbeanServer server) {
protected BeanRepository(Class<T> type, Database server) {
super(type, server);
}
@@ -75,7 +75,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
*
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
* @see Database#markAsDirty(Object)
*/
public void markAsDirty(T bean) {
db().markAsDirty(bean);
@@ -111,7 +111,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#save(Object)
* @see Database#save(Object)
*/
public void save(T bean) {
db().save(bean);
@@ -127,7 +127,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Update this entity.
*
* @see EbeanServer#update(Object)
* @see Database#update(Object)
*/
public void update(T bean) {
db().update(bean);
@@ -136,7 +136,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Insert this entity.
*
* @see EbeanServer#insert(Object)
* @see Database#insert(Object)
*/
public void insert(T bean) {
db().insert(bean);
@@ -157,7 +157,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
* @see Database#delete(Object)
*/
public boolean delete(T bean) {
return db().delete(bean);
@@ -177,7 +177,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* want to perform a hard/permanent delete.
* </p>
*
* @see EbeanServer#deletePermanent(Object)
* @see Database#deletePermanent(Object)
*/
public boolean deletePermanent(T bean) {
return db().deletePermanent(bean);
@@ -189,7 +189,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#merge(Object)
* @see Database#merge(Object)
*/
public void merge(T bean) {
db().merge(bean);
@@ -201,7 +201,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#merge(Object, MergeOptions)
* @see Database#merge(Object, MergeOptions)
*/
public void merge(T bean, MergeOptions options) {
db().merge(bean, options);
@@ -210,7 +210,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Refreshes this entity from the database.
*
* @see EbeanServer#refresh(Object)
* @see Database#refresh(Object)
*/
public void refresh(T bean) {
db().refresh(bean);
+9 -2
View File
@@ -1,5 +1,6 @@
package io.ebean;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;
@@ -56,7 +57,7 @@ public interface BeanState {
*
* // set loaded state on the email property to false so that
* // the email property is not included in a stateless update
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
* DB.getBeanState(user).setPropertyLoaded("email", false);
*
* user.update();
*
@@ -101,7 +102,7 @@ public interface BeanState {
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
* {@link Database#createEntityBean(Class)}, then populate its properties
* and then call this method specifying which properties where loaded or null
* for a fully loaded entity bean.
*/
@@ -111,4 +112,10 @@ public interface BeanState {
* Reset the bean putting it into NEW state such that a save() results in an insert.
*/
void resetForInsert();
/**
* Returns a map with load erros.
*/
@Nullable
Map<String, Exception> getLoadErrors();
}
+16 -18
View File
@@ -17,11 +17,11 @@ import java.sql.SQLException;
*
* String sql = "{call sp_order_mod(?,?)}";
*
* CallableSql cs = Ebean.createCallableSql(sql);
* CallableSql cs = DB.createCallableSql(sql);
* cs.setParameter(1, "turbo");
* cs.registerOut(2, Types.INTEGER);
*
* Ebean.execute(cs);
* DB.execute(cs);
*
* // read the out parameter
* Integer returnValue = (Integer) cs.getObject(2);
@@ -38,7 +38,7 @@ import java.sql.SQLException;
*
* String sql = "{call sp_insert_order(?,?)}";
*
* CallableSql cs = Ebean.createCallableSql(sql);
* CallableSql cs = DB.createCallableSql(sql);
*
* // Inform Ebean this stored procedure inserts into the
* // oe_order table and inserts + updates the oe_order_detail table.
@@ -46,35 +46,33 @@ import java.sql.SQLException;
* cs.addModification("oe_order", true, false, false);
* cs.addModification("oe_order_detail", true, true, false);
*
* Transaction t = Ebean.startTransaction();
*
* // execute using JDBC batching 10 statements at a time
* t.setBatchMode(true);
* t.setBatchSize(10);
* try {
* try (Transaction t = DB.beginTransaction()) {
*
* // execute using JDBC batching 10 statements at a time
* t.setBatchMode(true);
* t.setBatchSize(10);
*
* cs.setParameter(1, "Was");
* cs.setParameter(2, "Banana");
* Ebean.execute(cs);
* DB.execute(cs);
*
* cs.setParameter(1, "Here");
* cs.setParameter(2, "Kumera");
* Ebean.execute(cs);
* DB.execute(cs);
*
* cs.setParameter(1, "More");
* cs.setParameter(2, "Apple");
* Ebean.execute(cs);
* DB.execute(cs);
*
* // Ebean.externalModification("oe_order",true,false,false);
* // Ebean.externalModification("oe_order_detail",true,true,false);
* Ebean.commitTransaction();
* // DB.externalModification("oe_order",true,false,false);
* // DB.externalModification("oe_order_detail",true,true,false);
* t.commit();
*
* } finally {
* Ebean.endTransaction();
* }
* }</pre>
*
* @see SqlUpdate
* @see Ebean#execute(CallableSql)
*/
public interface CallableSql {
@@ -173,7 +171,7 @@ public interface CallableSql {
* Add table modification information to the TransactionEvent.
* <p>
* This would be similar to using the
* <code>Ebean.externalModification()</code> method. It may be easier and make
* <code>DB.externalModification()</code> method. It may be easier and make
* more sense to set it here with the CallableSql.
* </p>
* <p>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
package io.ebean;
import io.ebean.config.ContainerConfig;
import io.ebean.config.DatabaseConfig;
/**
* Creates Database instances.
* <p>
* This uses either DatabaseConfig or properties in the application.properties file to
* configure and create a Database instance.
* </p>
* <p>
* The Database instance can either be registered with the DB singleton or
* not. The DB singleton effectively holds a map of Database by a name.
* If the Database is registered with the DB singleton you can retrieve it
* later via {@link DB#byName(String)}.
* </p>
* <p>
* One Database can be nominated as the 'default/primary' Database. Many
* methods on the DB singleton such as {@link DB#find(Class)} are just a
* convenient way of using the 'default/primary' Database.
* </p>
*/
public class DatabaseFactory {
/**
* Initialise the container with clustering configuration.
* <p>
* Call this prior to creating any Database instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first Database instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
EbeanServerFactory.initialiseContainer(containerConfig);
}
/**
* Create using ebean.properties to configure the server.
*/
public static synchronized Database create(String name) {
return EbeanServerFactory.create(name);
}
/**
* Create using the ServerConfig object to configure the server.
*/
public static synchronized Database create(DatabaseConfig config) {
return EbeanServerFactory.create(config);
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
return EbeanServerFactory.createWithContextClassLoader(config, classLoader);
}
/**
* Shutdown gracefully all Database instances cleaning up any resources as required.
* <p>
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
EbeanServerFactory.shutdown();
}
}
+7 -1
View File
@@ -30,7 +30,7 @@ import java.util.function.Predicate;
* String sql = "select id, name from customer where name like :name and status_code = :status";
*
* List<CustomerDto> beans =
* Ebean.findDto(CustomrDto.class, sql)
* DB.findDto(CustomerDto.class, sql)
* .setParameter("name", "Acme%")
* .setParameter("status", "ACTIVE")
* .findList();
@@ -109,6 +109,12 @@ public interface DtoQuery<T> {
*/
DtoQuery<T> setLabel(String label);
/**
* Set the profile location of this query. This is used to relate query execution metrics
* back to a location like a specific line of code.
*/
DtoQuery<T> setProfileLocation(ProfileLocation profileLocation);
/**
* Set a timeout on this query.
* <p>
+27 -103
View File
@@ -2,7 +2,9 @@ package io.ebean;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.BeanNotEnhancedException;
import io.ebean.config.ServerConfig;
import io.ebean.datasource.DataSourceConfigurationException;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
@@ -22,113 +24,26 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
* This Ebean object is effectively a singleton that holds a map of registered
* {@link EbeanServer}s. It additionally provides a convenient way to use the
* 'default' EbeanServer.
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
* <p>
* If you are using a Dependency Injection framework such as
* <strong>Spring</strong> or <strong>Guice</strong> you will probably
* <strong>NOT</strong> use this Ebean singleton object. Instead you will
* configure and construct EbeanServer instances using {@link ServerConfig} and
* {@link EbeanServerFactory} and inject those EbeanServer instances into your
* data access objects.
* </p>
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
* <p>
* In documentation "Ebean singleton" refers to this object.
* </p>
* <ul>
* <li>There is one EbeanServer per Database (javax.sql.DataSource).</li>
* <li>EbeanServers can be 'registered' with the Ebean singleton (put into its
* map). Registered EbeanServer's can later be retrieved via
* {@link #getServer(String)}.</li>
* <li>One EbeanServer can be referred to as the 'default' EbeanServer. For
* convenience, the Ebean singleton (this object) provides methods such as
* {@link #find(Class)} that proxy through to the 'default' EbeanServer. This
* can be useful for applications that use a single database.</li>
* </ul>
* <p>
* For developer convenience Ebean has static methods that proxy through to the
* methods on the <em>'default'</em> EbeanServer. These methods are provided for
* developers who are mostly using a single database. Many developers will be
* able to use the methods on Ebean rather than get a EbeanServer.
* </p>
* <p>
* EbeanServers can be created and used without ever needing or using the Ebean
* singleton. Refer to {@link ServerConfig#setRegister(boolean)}.
* </p>
* <p>
* You can either programmatically create/register EbeanServers via
* {@link EbeanServerFactory} or they can automatically be created and
* registered when you first use the Ebean singleton. When EbeanServers are
* created automatically they are configured using information in the
* ebean.properties file.
* </p>
* <pre>{@code
*
* // fetch shipped orders (and also their customer)
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer")
* .where()
* .eq("status.code", Order.Status.SHIPPED)
* .findList();
*
* // read/use the order list ...
* for (Order order : list) {
* Customer customer = order.getCustomer();
* ...
* }
*
* }</pre>
* <pre>{@code
*
* // fetch order 10, modify and save
* Order order = Ebean.find(Order.class, 10);
*
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
* order.setStatus(shipped);
* order.setShippedDate(shippedDate);
* ...
*
* // implicitly creates a transaction and commits
* Ebean.save(order);
*
* }</pre>
* <p>
* When you have multiple databases and need access to a specific one the
* {@link #getServer(String)} method provides access to the EbeanServer for that
* specific database.
* </p>
* <pre>{@code
*
* // Get access to the Human Resources EbeanServer/Database
* EbeanServer hrDb = Ebean.getServer("hr");
*
* // fetch contact 3 from the HR database
* Contact contact = hrDb.find(Contact.class, 3);
*
* contact.setName("I'm going to change");
* ...
*
* // save the contact back to the HR database
* hrDb.save(contact);
*
* }</pre>
* The preference is to use DB and Database rather than Ebean and EbeanServer.
*/
public final class Ebean {
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
static {
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
EbeanVersion.getVersion(); // initialises the version class and logs the version.
}
/**
* Manages creation and cache of EbeanServers.
* Manages creation and cache of Databases.
*/
private static final Ebean.ServerManager serverMgr = new Ebean.ServerManager();
/**
* Helper class for managing fast and safe access and creation of
* EbeanServers.
* Helper class for managing fast and safe access and creation of Databases.
*/
private static final class ServerManager {
@@ -145,7 +60,7 @@ public final class Ebean {
private final Object monitor = new Object();
/**
* The 'default' EbeanServer.
* The 'default' Database.
*/
private EbeanServer defaultServer;
@@ -160,15 +75,24 @@ public final class Ebean {
defaultServer = getWithCreate(defaultName.trim());
}
}
} catch (BeanNotEnhancedException e) {
throw e;
} catch (DataSourceConfigurationException e) {
String msg = "Configuration error creating DataSource for the default Database." +
" This typically means a missing application-test.yaml or missing ebean-test-config dependency." +
" See https://ebean.io/docs/trouble-shooting#datasource";
throw new DataSourceConfigurationException(msg, e);
} catch (Throwable e) {
logger.error("Error trying to create the default EbeanServer", e);
logger.error("Error trying to create the default Database", e);
throw new RuntimeException(e);
}
}
private EbeanServer getDefaultServer() {
if (defaultServer == null) {
String msg = "The default EbeanServer has not been defined?";
String msg = "The default Database has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programmatically via registerServer()";
throw new PersistenceException(msg);
@@ -190,7 +114,7 @@ public final class Ebean {
}
/**
* Synchronized read, create and put of EbeanServers.
* Synchronized read, create and put of Databases.
*/
private EbeanServer getWithCreate(String name) {
@@ -229,7 +153,7 @@ public final class Ebean {
}
/**
* Get the EbeanServer for a given DataSource. If name is null this will
* Get the Database for a given DataSource. If name is null this will
* return the 'default' EbeanServer.
* <p>
* This is provided to access EbeanServer for databases other than the
@@ -620,7 +544,8 @@ public final class Ebean {
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
* ebeanServer.update(customer);
*
* DB.update(customer);
*
* }</pre>
*
@@ -1120,10 +1045,9 @@ public final class Ebean {
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
*
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
* query.setParameter(1, "Rob%");
*
* List<Customer> customers = query.findList();
* List<Customer> customers = DB.findNative(Customer.class, sql)
* .setParameter(1, "Rob%")
* .findList()
*
* }</pre>
*
File diff suppressed because it is too large Load Diff
@@ -22,8 +22,8 @@ package io.ebean;
* example.setName("Rob%");
* example.setNotes("%something%");
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* List<Customer> list =
* DB.find(Customer.class)
* .where()
* // pass the bean into the where() clause
* .exampleLike(example)
@@ -46,7 +46,7 @@ package io.ebean;
* .includeZeros();
*
* List<Customer> list =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .where()
* .add(qbe)
* .findList();
+50 -17
View File
@@ -13,27 +13,15 @@ import java.util.Map;
* {@link Query#where()}.
* </p>
* <p>
* This provides a convenient way to create expressions for the 'Default'
* server. It is actually a short cut for using the ExpressionFactory of the
* 'default' EbeanServer.
* This provides a convenient way to create expressions for the default
* database.
* <p>
* See also {@link Ebean#getExpressionFactory()}
* See also {@link DB#getExpressionFactory()}
* </p>
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
* <pre>{@code
*
* // Example: Using an Expr.or() method
* Query<Order> query = Ebean.createQuery(Order.class);
* query.where(
* Expr.or(Expr.eq("status", Order.NEW),
* Expr.gt("orderDate", lastWeek));
*
* List<Order> list = query.findList();
* ...
* }</pre>
*
* @see Query#where()
*/
@@ -64,11 +52,20 @@ public class Expr {
return Ebean.getExpressionFactory().ieq(propertyName, value);
}
/**
* In Range - property >= value1 and property < value2.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
*/
public static Expression inRange(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().inRange(propertyName, value1, value2);
}
/**
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
}
@@ -76,7 +73,6 @@ public class Expr {
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
@@ -242,6 +238,43 @@ public class Expr {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
+97 -3
View File
@@ -30,9 +30,9 @@ import java.util.Map;
* Expr.or(Expr.eq("status", Order.Status.NEW),
* Expr.gt("orderDate", lastWeek));
*
* Query<Order> query = Ebean.createQuery(Order.class);
* query.where().add(newOrLastWeek);
* List<Order> list = query.findList();
* List<Order> list = DB.find(Order.class)
* .where().add(newOrLastWeek)
* .findList();
* ...
* }</pre>
*
@@ -122,6 +122,11 @@ public interface ExpressionFactory {
*/
Expression eq(String propertyName, Object value);
/**
* Equal To or Null - property equal to the given value or null.
*/
Expression eqOrNull(String propertyName, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
@@ -133,11 +138,49 @@ public interface ExpressionFactory {
*/
Expression ieq(String propertyName, String value);
/**
* Case Insensitive Not Equal To - property not equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
Expression ine(String propertyName, String value);
/**
* Case Insensitive Equal To that allows for named parameter use.
*/
Expression ieqObject(String propertyName, Object value);
/**
* Case Insensitive Not Equal To that allows for named parameter use.
*/
Expression ineObject(String propertyName, Object value);
/**
* In Range - property >= value1 and property < value2.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
*/
Expression inRange(String propertyName, Object value1, Object value2);
/**
* Value in Range between 2 properties.
*
* <pre>{@code
*
* .startDate.inRangeWith(endDate, now)
*
* // which equates to
* startDate <= now and (endDate > now or endDate is null)
*
* }</pre>
*
* <p>
* This is a convenience expression combining a number of simple expressions.
* The most common use of this could be called "effective dating" where 2 date or
* timestamp columns represent the date range in which
*/
Expression inRangeWith(String lowProperty, String highProperty, Object value);
/**
* Between - property between the two given values.
*/
@@ -148,6 +191,14 @@ public interface ExpressionFactory {
*/
Expression betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than Or Null - property greater than the given value or null.
* <p>
* A convenient expression combining GT and Is Null. Most often useful for range
* expressions where the top range value is nullable.
*/
Expression gtOrNull(String propertyName, Object value);
/**
* Greater Than - property greater than the given value.
*/
@@ -159,6 +210,14 @@ public interface ExpressionFactory {
*/
Expression ge(String propertyName, Object value);
/**
* Less Than or Null - property less than the given value or null.
* <p>
* A convenient expression combining LT and Is Null. Most often useful for range
* expressions where the bottom range value is nullable.
*/
Expression ltOrNull(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
@@ -266,6 +325,41 @@ public interface ExpressionFactory {
*/
Expression in(String propertyName, Collection<?> values);
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
Expression inOrEmpty(String propertyName, Collection<?> values);
/**
* Not In - property has a value in the array of values.
*/
+270 -55
View File
@@ -128,6 +128,38 @@ public interface ExpressionList<T> {
*/
<D> DtoQuery<D> asDto(Class<D> dtoClass);
/**
* Return the underlying query as an UpdateQuery.
* <p>
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
* </p>
*
* <pre>{@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }</pre>
*
* <pre>{@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }</pre>
*/
UpdateQuery<T> asUpdate();
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
@@ -166,6 +198,18 @@ public interface ExpressionList<T> {
*/
int delete();
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @return the number of rows that were deleted.
*/
int delete(Transaction transaction);
/**
* Execute as a update query.
*
@@ -174,6 +218,40 @@ public interface ExpressionList<T> {
*/
int update();
/**
* Execute as a update query with the given transaction.
*
* @return the number of rows that were updated.
* @see UpdateQuery
*/
int update(Transaction transaction);
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query iterating over the results.
*
@@ -238,23 +316,23 @@ public interface ExpressionList<T> {
/**
* Execute the query returning a list of values for a single property.
* <p>
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
* <p>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
@@ -271,11 +349,10 @@ public interface ExpressionList<T> {
/**
* Execute a query returning a single value of a single property/column.
* <p>
* <pre>{@code
*
* String name =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
@@ -356,10 +433,9 @@ public interface ExpressionList<T> {
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
* <p>
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* PagedList<Order> pagedList = DB.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
@@ -426,7 +502,7 @@ public interface ExpressionList<T> {
* <pre>{@code
*
* List<Customer> customers =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name") // only select the customer name
* .findList();
@@ -495,12 +571,11 @@ public interface ExpressionList<T> {
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
* <p>
* <pre>{@code
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* Ebean.find(Order.class)
* DB.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
@@ -605,7 +680,6 @@ public interface ExpressionList<T> {
/**
* Equal to expression for the value at the given path in the JSON document.
* <p>
* <pre>{@code
*
* where().jsonEqualTo("content", "path.other", 34)
@@ -620,7 +694,6 @@ public interface ExpressionList<T> {
/**
* Not Equal to - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonNotEqualTo("content", "path.other", 34)
@@ -635,7 +708,6 @@ public interface ExpressionList<T> {
/**
* Greater than - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonGreaterThan("content", "path.other", 34)
@@ -646,7 +718,6 @@ public interface ExpressionList<T> {
/**
* Greater than or equal to - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonGreaterOrEqual("content", "path.other", 34)
@@ -657,7 +728,6 @@ public interface ExpressionList<T> {
/**
* Less than - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonLessThan("content", "path.other", 34)
@@ -668,7 +738,6 @@ public interface ExpressionList<T> {
/**
* Less than or equal to - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonLessOrEqualTo("content", "path.other", 34)
@@ -679,7 +748,6 @@ public interface ExpressionList<T> {
/**
* Between - for the given path in a JSON document.
* <p>
* <pre>{@code
*
* where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
@@ -690,21 +758,6 @@ public interface ExpressionList<T> {
/**
* Add an Expression to the list.
* <p>
* This returns the list so that add() can be chained.
* </p>
* <p>
* <pre>{@code
*
* Query<Customer> query = Ebean.find(Customer.class);
* query.where()
* .like("name","Rob%")
* .eq("status", Customer.ACTIVE);
*
* List<Customer> list = query.findList();
* ...
*
* }</pre>
*/
ExpressionList<T> add(Expression expr);
@@ -718,6 +771,11 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> eq(String propertyName, Object value);
/**
* Equal To or Null - property is equal to a given value or null.
*/
ExpressionList<T> eqOrNull(String propertyName, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
@@ -730,8 +788,41 @@ public interface ExpressionList<T> {
ExpressionList<T> ieq(String propertyName, String value);
/**
* Between - property between the two given values.
* Case Insensitive Not Equal To - property not equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
ExpressionList<T> ine(String propertyName, String value);
/**
* Value in Range between 2 properties.
*
* <pre>{@code
*
* .startDate.inRangeWith(endDate, now)
*
* // which equates to
* startDate <= now and (endDate > now or endDate is null)
*
* }</pre>
*
* <p>
* This is a convenience expression combining a number of simple expressions.
* The most common use of this could be called "effective dating" where 2 date or
* timestamp columns represent the date range in which
*/
ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value);
/**
* In Range - property >= value1 and property < value2.
* <p>
* Unlike Between inRange is "half open" and usually more useful for use with dates or timestamps.
* </p>
*/
ExpressionList<T> inRange(String propertyName, Object value1, Object value2);
/**
* Between - property between the two given values.
*/
ExpressionList<T> between(String propertyName, Object value1, Object value2);
/**
@@ -744,6 +835,11 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> gt(String propertyName, Object value);
/**
* Greater Than or Null - property greater than the given value or null.
*/
ExpressionList<T> gtOrNull(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
@@ -755,6 +851,11 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> lt(String propertyName, Object value);
/**
* Less Than or Null - property less than the given value or null.
*/
ExpressionList<T> ltOrNull(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
@@ -784,7 +885,6 @@ public interface ExpressionList<T> {
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
* <p>
* <pre>{@code
*
* // create an example bean and set the properties
@@ -793,16 +893,15 @@ public interface ExpressionList<T> {
* example.setName("Rob%");
* example.setNotes("%something%");
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt("id", 2).findList();
* List<Customer> list =
* DB.find(Customer.class)
* .where().exampleLike(example)
* .findList();
*
* }</pre>
* <p>
* Similarly you can create an ExampleExpression
* <p>
* </p>
* <pre>{@code
*
* Customer example = new Customer();
@@ -812,7 +911,7 @@ public interface ExpressionList<T> {
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
*
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
* List<Customer> list = DB.find(Customer.class).where().add(qbe).findList();
*
* }</pre>
*/
@@ -889,6 +988,41 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> in(String propertyName, Collection<?> values);
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* if (ids != null && !ids.isEmpty()) {
* query.where().in("customer.id", ids);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .inOrEmpty("customer.id", ids)
* .findList();
*
* }</pre>
*/
ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values);
/**
* In - using a subQuery.
* <p>
@@ -1024,7 +1158,6 @@ public interface ExpressionList<T> {
/**
* Add expression for ALL of the given bit flags to be set.
* <p>
* <pre>{@code
*
* where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
@@ -1038,7 +1171,6 @@ public interface ExpressionList<T> {
/**
* Add expression for the given bit flags to be NOT set.
* <p>
* <pre>{@code
*
* where().bitwiseNot("flags", BwFlags.HAS_COLOUR)
@@ -1089,6 +1221,13 @@ public interface ExpressionList<T> {
* raw("add_days(orderDate, 10) < ?", someDate)
*
* }</pre>
*
* <h4>Subquery example:</h4>
* <pre>{@code
*
* .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
*
* }</pre>
*/
ExpressionList<T> raw(String raw, Object value);
@@ -1113,15 +1252,83 @@ public interface ExpressionList<T> {
* then they are not translated. logical property name names (not fully
* qualified) will still be translated to their physical name.
* </p>
* <p>
* <pre>{@code
*
* raw("orderQty < shipQty")
*
* }</pre>
*
* <h4>Subquery example:</h4>
* <pre>{@code
*
* .raw("t0.customer_id in (select customer_id from customer_group where group_id = any(?::uuid[]))", groupIds)
*
* }</pre>
*/
ExpressionList<T> raw(String raw);
/**
* Only add the raw expression if the values is not null or empty.
* <p>
* This is a pure convenience expression to make it nicer to deal with the pattern where we use
* raw() expression with a subquery and only want to add the subquery predicate when the collection
* of values is not empty.
* </p>
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* query.where() // add some predicates
* .eq("status", Status.NEW);
*
* // common pattern - we can use rawOrEmpty() instead
* if (orderIds != null && !orderIds.isEmpty()) {
* query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using rawOrEmpty()</h3>
* Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion"
* for each element in the collection.
*
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* // only add the expression if orderIds is not empty
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
* .findList();
*
* }</pre>
*
* <h3>Postgres ANY</h3>
* With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
* rather than <code>IN</code>.
*
* <pre>{@code
*
* query.where()
* .eq("status", Status.NEW)
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
* .findList();
*
* }</pre>
* <p>
* Note that we need to cast the Postgres array for UUID types like:
* </p>
* <pre>{@code
*
* " ... = any(?::uuid[])"
*
* }</pre>
*
* @param raw The raw expression that is typically a subquery
* @param values The values which is typically a list or set of id values.
*/
ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
/**
* Add a match expression.
*
@@ -1192,12 +1399,10 @@ public interface ExpressionList<T> {
* typically you only explicitly need to use the and() junction
* when it is nested inside an or() or not() junction.
* </p>
* <p>
* <pre>{@code
*
* // Example: Nested and()
*
* Ebean.find(Customer.class)
* .where()
* .or()
* .and() // nested and
@@ -1218,16 +1423,27 @@ public interface ExpressionList<T> {
* Return a list of expressions that will be joined by OR's.
* This is exactly the same as disjunction();
* <p>
* <p>
* Use endOr() or endJunction() to end the OR junction.
* </p>
* <p>
*
* <pre>{@code
*
* // Example: (status active OR anniversary is null)
*
* .where()
* .or()
* .eq("status", Customer.Status.ACTIVE)
* .isNull("anniversary")
* .orderBy().asc("name")
* .findList();
*
* }</pre>
*
* <pre>{@code
*
* // Example: Use or() to join
* // two nested and() expressions
*
* Ebean.find(Customer.class)
* .where()
* .or()
* .and()
@@ -1251,8 +1467,8 @@ public interface ExpressionList<T> {
* Use endNot() or endJunction() to end expressions being added to the
* NOT expression list.
* </p>
* <p>
* <pre>@{code
*
* <pre>{@code
*
* .where()
* .not()
@@ -1261,12 +1477,11 @@ public interface ExpressionList<T> {
* .endNot()
*
* }</pre>
* <p>
* <pre>@{code
*
* <pre>{@code
*
* // Example: nested not()
*
* Ebean.find(Customer.class)
* .where()
* .eq("status", Customer.Status.ACTIVE)
* .not()
+39 -12
View File
@@ -1,5 +1,8 @@
package io.ebean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiTransaction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -12,7 +15,7 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* The extended API for EbeanServer.
* The extended API for Database.
* <p>
* This provides the finder methods that take an explicit transaction rather than obtaining
* the transaction from the usual mechanism (which is ThreadLocal based).
@@ -23,7 +26,7 @@ import java.util.function.Predicate;
* the transaction to use.
* </p>
* <p>
* Note that in all cases the transaction supplied can be null and in this case the EbeanServer
* Note that in all cases the transaction supplied can be null and in this case the Database
* will use the normal mechanism to obtain the transaction to use.
* </p>
*/
@@ -42,6 +45,32 @@ public interface ExtendedServer {
*/
void setClock(Clock clock);
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
<T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction);
/**
* Return the number of 'top level' or 'root' entities this query should return.
*
@@ -92,7 +121,7 @@ public interface ExtendedServer {
* <p>
* <pre>{@code
*
* ebeanServer.find(Order.class)
* DB.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findEach((Order order) -> {
@@ -126,7 +155,7 @@ public interface ExtendedServer {
* <p>
* <pre>{@code
*
* ebeanServer.find(Order.class)
* DB.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findEachWhile((Order order) -> {
@@ -165,8 +194,7 @@ public interface ExtendedServer {
* <p>
* <pre>{@code
*
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findList();
*
@@ -243,7 +271,7 @@ public interface ExtendedServer {
* <p>
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* PagedList<Order> pagedList = DB.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
@@ -272,8 +300,7 @@ public interface ExtendedServer {
* <p>
* <pre>{@code
*
* Set<Customer> customers =
* ebeanServer.find(Customer.class)
* Set<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findSet();
*
@@ -312,7 +339,7 @@ public interface ExtendedServer {
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
@@ -322,7 +349,7 @@ public interface ExtendedServer {
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
@@ -384,7 +411,7 @@ public interface ExtendedServer {
/**
* Execute the update query returning the number of rows updated.
* <p>
* The update query must be created using {@link EbeanServer#update(Class)}.
* The update query must be created using {@link Database#update(Class)}.
* </p>
*
* @param query the update query to execute
+6 -6
View File
@@ -24,7 +24,7 @@ import java.io.Serializable;
* <p>
* <pre>{@code
* // Normal fetch join results in a single SQL query
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
* List<Order> list = DB.find(Order.class).fetch("details").findList();
*
* // Find Orders join details using a single SQL query
* }</pre>
@@ -36,7 +36,7 @@ import java.io.Serializable;
*
* // This will use 2 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* DB.find(Order.class)
* .fetch("details", new FetchConfig().query())
* .findList();
*
@@ -52,7 +52,7 @@ import java.io.Serializable;
*
* // This will use 3 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* DB.find(Order.class)
* .fetch("details", new FetchConfig().query())
* .fetch("customer", new FetchConfig().queryFirst(5))
* .findList();
@@ -70,7 +70,7 @@ import java.io.Serializable;
* <pre>{@code
* // This will use 3 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* DB.find(Order.class)
* .select("status, shipDate")
* .fetch("details", "quantity, price", new FetchConfig().query())
* .fetch("details.product", "sku, name")
@@ -100,7 +100,7 @@ import java.io.Serializable;
* <pre>{@code
*
* List<Order> list =
* Ebean.find(Order.class)
* DB.find(Order.class)
* .fetch("customer", new FetchConfig().query(10).lazy(5))
* .findList();
*
@@ -121,7 +121,7 @@ import java.io.Serializable;
* <p>
* <pre>{@code
*
* List<Order> list = Ebean.find(Order.class)
* List<Order> list = DB.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts","contactName, phone, email")
* .fetch("customer.shippingAddress")
+1 -1
View File
@@ -10,7 +10,7 @@ import javax.annotation.Nonnull;
* that can be defined separately from the query and combined with other FetchGroups.
* </p>
*
* <h3>Select example</h3>*
* <h3>Select example</h3>
* <pre>{@code
*
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class, "name, status");
+4 -4
View File
@@ -25,14 +25,14 @@ import java.util.Set;
* // get a list of entities (query execution statistics in this case)
*
* List<MetaQueryStatistic> list =
* Ebean.find(MetaQueryStatistic.class).findList();
* DB.find(MetaQueryStatistic.class).findList();
*
* long nowMinus24Hrs = System.currentTimeMillis() - 24 * (1000 * 60 * 60);
*
* // sort and filter the list returning a filtered list...
*
* List<MetaQueryStatistic> filteredList =
* Ebean.filter(MetaQueryStatistic.class)
* DB.filter(MetaQueryStatistic.class)
* .sort("avgTimeMicros desc")
* .gt("executionCount", 0)
* .gt("lastQueryTime", nowMinus24Hrs)
@@ -63,12 +63,12 @@ import java.util.Set;
* // get a list of entities (query execution statistics)
*
* List<Order> orders =
* Ebean.find(Order.class).findList();
* DB.find(Order.class).findList();
*
* // Apply a filter...
*
* List<Order> filteredOrders =
* Ebean.filter(Order.class)
* DB.filter(Order.class)
* .startsWith("customer.name", "Rob")
* .eq("customer.shippingAddress.city", "Auckland")
* .filter(orders);
+30 -26
View File
@@ -2,7 +2,6 @@ package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
/**
@@ -14,8 +13,7 @@ import java.util.List;
* </p>
* <h3>Testing</h3>
* <p>
* For testing the mocki-ebean project has the ability to replace the finder implementation
* <p>
* For testing the mocki-ebean project has the ability to replace the finder implementation.
* </p>
* <pre>{@code
*
@@ -25,7 +23,7 @@ import java.util.List;
* super(Customer.class);
* }
*
* // Add your customer finder methods ...
* // Add finder methods ...
*
* public Customer byName(String name) {
* return query().eq("name", name).findOne();
@@ -46,6 +44,15 @@ import java.util.List;
* ...
*
* }</pre>
* <p>
* When the Finder is registered as a field on Customer it can then be used like:
* </p>
* <pre>{@code
*
* Customer rob = Customer.find.byName("Rob");
*
* }</pre>
*
*/
public class Finder<I, T> {
@@ -55,9 +62,9 @@ public class Finder<I, T> {
private final Class<T> type;
/**
* The name of the EbeanServer, null for the default server.
* The name of the database this finder will use, null for the default database.
*/
private final String serverName;
private final String _$dbName;
/**
* Create with the type of the entity bean.
@@ -82,15 +89,15 @@ public class Finder<I, T> {
*/
public Finder(Class<T> type) {
this.type = type;
this.serverName = null;
this._$dbName = null;
}
/**
* Create with the type of the entity bean and specific server name.
* Create with the type of the entity bean and specific database name.
*/
public Finder(Class<T> type, String serverName) {
public Finder(Class<T> type, String databaseName) {
this.type = type;
this.serverName = serverName;
this._$dbName = databaseName;
}
/**
@@ -108,30 +115,27 @@ public class Finder<I, T> {
}
/**
* Return the underlying 'default' EbeanServer.
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
* Return the Database this finder will use.
*/
public EbeanServer db() {
return Ebean.getServer(serverName);
public Database db() {
return DB.byName(_$dbName);
}
/**
* Return typically a different EbeanServer to the default.
* Return typically a different Database to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
* This is equivalent to {@link DB#byName(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
* @param databaseName The name of the Database. If this is null then the default database is returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
public Database db(String databaseName) {
return DB.byName(databaseName);
}
/**
* Creates an entity reference for this ID.
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
* Equivalent to {@link Database#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
@@ -141,7 +145,7 @@ public class Finder<I, T> {
/**
* Retrieves an entity by ID.
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
* Equivalent to {@link Database#find(Class, Object)}
*/
@Nullable
public T byId(I id) {
@@ -151,7 +155,7 @@ public class Finder<I, T> {
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
* Equivalent to {@link Database#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
@@ -181,7 +185,7 @@ public class Finder<I, T> {
* }</pre>
*
* <p>
* Equivalent to {@link EbeanServer#update(Class)}
* Equivalent to {@link Database#update(Class)}
*/
public UpdateQuery<T> update() {
return db().update(type);
@@ -190,7 +194,7 @@ public class Finder<I, T> {
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
* Equivalent to {@link Database#find(Class)}
*/
public Query<T> query() {
return db().find(type);
+1 -1
View File
@@ -20,7 +20,7 @@ import java.util.concurrent.TimeoutException;
* <pre>{@code
*
* // create a query to find all orders
* Query<Order> query = Ebean.find(Order.class);
* Query<Order> query = DB.find(Order.class);
*
* // execute the query in a background thread
* // immediately returning the futureList
+3 -3
View File
@@ -11,7 +11,7 @@ package io.ebean;
* </p>
* <pre>{@code
* Query q =
* Ebean.find(Person.class)
* DB.find(Person.class)
* .where()
* .or()
* .like("name", "Rob%")
@@ -30,7 +30,7 @@ package io.ebean;
* <pre>{@code
*
* Query q =
* Ebean.find(Person.class)
* DB.find(Person.class)
* .where()
* .or()
* .like("name", "Rob%")
@@ -50,7 +50,7 @@ package io.ebean;
* </p>
* <pre>{@code
* Query<Customer> q =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .where()
* .or()
* .and()
@@ -78,6 +78,7 @@ public class MergeOptionsBuilder {
this.deletePermanent = deletePermanent;
}
@Override
public Set<String> paths() {
return paths;
}
+19 -27
View File
@@ -2,7 +2,6 @@ package io.ebean;
import io.ebean.bean.EntityBean;
import javax.persistence.MappedSuperclass;
/**
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
@@ -12,15 +11,15 @@ import javax.persistence.MappedSuperclass;
* Ebean users.
* <p>
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
* tools to still mock out the underlying 'default Database' for testing purposes.
* <p>
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
* or if you believe it 'pollutes' your entity beans.
* <p>
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
* You can use Dependency Injection like Guice or Spring to construct and wire a Database instance
* and have that same instance used with this Model and Finder. The way that works is that when the
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
* DI container creates the Database instance it can be registered with DB. In this
* way the Database instance can be injected as per normal Guice / Spring dependency injection and
* that same instance also used to support the Model and Finder active record style.
* <p>
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
@@ -74,19 +73,17 @@ import javax.persistence.MappedSuperclass;
*
* }</pre>
*/
@MappedSuperclass
public abstract class Model {
/**
* Return the underlying 'default' EbeanServer.
* Return the underlying 'default' Database.
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
* <p>
* Example:
* <pre>{@code
*
* Transaction transaction = Customer.db().beginTransaction();
* try {
* try (Transaction transaction = Customer.db().beginTransaction()) {
*
* // turn off cascade persist for this transaction
* transaction.setPersistCascade(false);
@@ -106,26 +103,21 @@ public abstract class Model {
*
* transaction.commit();
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*/
public static EbeanServer db() {
return Ebean.getDefaultServer();
public static Database db() {
return DB.getDefault();
}
/**
* Return a named EbeanServer that is typically different to the default server.
* <p>
* If you are using multiple databases then each database has a name and maps to a single
* EbeanServer. You can use this method to get an EbeanServer for another database.
* Return a named Database that is typically different to the default database.
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is returned.
* @param server The name of the Database. If this is null then the default Database is returned.
*/
public static EbeanServer db(String server) {
return Ebean.getServer(server);
public static Database db(String server) {
return DB.byName(server);
}
/**
@@ -148,7 +140,7 @@ public abstract class Model {
*
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
* @see Database#markAsDirty(Object)
*/
public void markAsDirty() {
db().markAsDirty(this);
@@ -184,7 +176,7 @@ public abstract class Model {
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#save(Object)
* @see Database#save(Object)
*/
public void save() {
db().save(this);
@@ -204,7 +196,7 @@ public abstract class Model {
/**
* Update this entity.
*
* @see EbeanServer#update(Object)
* @see Database#update(Object)
*/
public void update() {
db().update(this);
@@ -213,7 +205,7 @@ public abstract class Model {
/**
* Insert this entity.
*
* @see EbeanServer#insert(Object)
* @see Database#insert(Object)
*/
public void insert() {
db().insert(this);
@@ -234,7 +226,7 @@ public abstract class Model {
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
* @see Database#delete(Object)
*/
public boolean delete() {
return db().delete(this);
@@ -247,7 +239,7 @@ public abstract class Model {
* want to perform a hard/permanent delete.
* </p>
*
* @see EbeanServer#deletePermanent(Object)
* @see Database#deletePermanent(Object)
*/
public boolean deletePermanent() {
return db().deletePermanent(this);
@@ -277,7 +269,7 @@ public abstract class Model {
/**
* Refreshes this entity from the database.
*
* @see EbeanServer#refresh(Object)
* @see Database#refresh(Object)
*/
public void refresh() {
db().refresh(this);
+63 -13
View File
@@ -1,9 +1,11 @@
package io.ebean;
import io.ebean.util.StringHelper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Represents an Order By for a Query.
@@ -74,6 +76,15 @@ public final class OrderBy<T> implements Serializable {
return query;
}
/**
* Add a property with ascending order to this OrderBy.
*/
public Query<T> asc(String propertyName, String collation) {
list.add(new Property(propertyName, true, collation));
return query;
}
/**
* Add a property with descending order to this OrderBy.
*/
@@ -83,6 +94,16 @@ public final class OrderBy<T> implements Serializable {
return query;
}
/**
* Add a property with descending order to this OrderBy.
*/
public Query<T> desc(String propertyName, String collation) {
list.add(new Property(propertyName, false, collation));
return query;
}
/**
* Return true if the property is known to be contained in the order by clause.
*/
@@ -231,6 +252,8 @@ public final class OrderBy<T> implements Serializable {
private boolean ascending;
private String collation;
private String nulls;
private String highLow;
@@ -247,17 +270,32 @@ public final class OrderBy<T> implements Serializable {
this.highLow = highLow;
}
public Property(String property, boolean ascending, String collation) {
this.property = property;
this.ascending = ascending;
this.collation = collation;
}
public Property(String property, boolean ascending, String collation, String nulls, String highLow) {
this.property = property;
this.ascending = ascending;
this.collation = collation;
this.nulls = nulls;
this.highLow = highLow;
}
/**
* Return a copy of this Property with the path trimmed.
*/
public Property copyWithTrim(String path) {
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
return new Property(property.substring(path.length() + 1), ascending, collation, nulls, highLow);
}
@Override
public int hashCode() {
int hc = property.hashCode();
hc = hc * 92821 + (ascending ? 0 : 1);
hc = hc * 92821 + (collation == null ? 0 : collation.hashCode());
hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode());
hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode());
return hc;
@@ -274,8 +312,9 @@ public final class OrderBy<T> implements Serializable {
Property e = (Property) obj;
if (ascending != e.ascending) return false;
if (!property.equals(e.property)) return false;
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
if (!Objects.equals(collation, e.collation)) return false;
if (!Objects.equals(nulls, e.nulls)) return false;
return Objects.equals(highLow, e.highLow);
}
@Override
@@ -284,7 +323,7 @@ public final class OrderBy<T> implements Serializable {
}
public String toStringFormat() {
if (nulls == null) {
if (nulls == null && collation == null) {
if (ascending) {
return property;
} else {
@@ -292,11 +331,23 @@ public final class OrderBy<T> implements Serializable {
}
} else {
StringBuilder sb = new StringBuilder();
sb.append(property);
if (collation != null) {
if (collation.contains("${}")) {
// this is a complex collation, e.g. DB2 - we must replace the property
sb.append(StringHelper.replaceString(collation, "${}", property));
} else {
sb.append(property);
sb.append(" collate ").append(collation);
}
} else {
sb.append(property);
}
if (!ascending) {
sb.append(" ").append("desc");
}
sb.append(" ").append(nulls).append(" ").append(highLow);
if (nulls != null) {
sb.append(" ").append(nulls).append(" ").append(highLow);
}
return sb.toString();
}
}
@@ -319,7 +370,7 @@ public final class OrderBy<T> implements Serializable {
* Return a copy of this property.
*/
public Property copy() {
return new Property(property, ascending, nulls, highLow);
return new Property(property, ascending, collation, nulls, highLow);
}
/**
@@ -360,15 +411,15 @@ public final class OrderBy<T> implements Serializable {
String[] chunks = orderByClause.split(",");
for (String chunk : chunks) {
String[] pairs = chunk.split(" ");
Property p = parseProperty(pairs);
Property p = parseProperty(chunk);
if (p != null) {
list.add(p);
}
}
}
private Property parseProperty(String[] pairs) {
private Property parseProperty(String chunk) {
String[] pairs = chunk.split(" ");
if (pairs.length == 0) {
return null;
}
@@ -394,8 +445,7 @@ public final class OrderBy<T> implements Serializable {
boolean asc = isAscending(wordList.get(1));
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
}
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
throw new RuntimeException(m);
return new Property(chunk.trim(), true);
}
private boolean isAscending(String s) {
+1 -2
View File
@@ -24,8 +24,7 @@ import java.util.concurrent.Future;
* // We want to find the first 50 new orders
* // ... so we don't really need setFirstRow(0)
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* PagedList<Order> pagedList = DB.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .setFirstRow(0)
+3 -2
View File
@@ -1,6 +1,7 @@
package io.ebean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -25,7 +26,7 @@ import java.util.List;
* pairs.add("sj2", 1001);
* pairs.add("pf3", 1000);
*
* List<OCachedNatKeyBean3> list = Ebean.find(OCachedNatKeyBean3.class)
* List<OCachedNatKeyBean3> list = DB.find(OCachedNatKeyBean3.class)
* .where()
* .eq("store", "def")
* .inPairs(pairs) // IN clause with 'pairs' of values
@@ -125,7 +126,7 @@ public class Pairs {
* Return all the value pairs.
*/
public List<Entry> getEntries() {
return entries;
return Collections.unmodifiableList(entries);
}
/**
@@ -40,6 +40,11 @@ public interface ProfileLocation {
*/
String shortDescription();
/**
* Return the short label.
*/
String label();
/**
* Add execution time.
*/
+189 -102
View File
@@ -19,10 +19,7 @@ import java.util.function.Predicate;
* <p>
* <pre>{@code
*
* List<Order> orderList =
* ebeanServer.find(Order.class)
* .fetch("customer")
* .fetch("details")
* List<Order> orderList = DB.find(Order.class)
* .where()
* .like("customer.name","rob%")
* .gt("orderDate",lastWeek)
@@ -38,29 +35,14 @@ import java.util.function.Predicate;
* <pre>{@code
*
* String oql =
* +" fetch customer "
* +" fetch details "
* +" where customer.name like :custName and orderDate > :minOrderDate "
* +" order by customer.id, id desc "
* +" limit 50 ";
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
* List<Order> orderList = query.findList();
* ...
* }</pre>
* <p>
* Example: Using a named query called "with.cust.and.details"
* </p>
* <pre>{@code
*
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
* query.setParameter("custName", "Rob%");
* query.setParameter("minOrderDate", lastWeek);
*
* List<Order> orderList = query.findList();
* List<Order> orderList = DB.createQuery(Order.class, oql)
* .setParameter("custName", "Rob%")
* .setParameter("minOrderDate", lastWeek)
* .findList();
* ...
* }</pre>
* <h3>AutoTune</h3>
@@ -244,6 +226,38 @@ public interface Query<T> {
*/
<D> DtoQuery<D> asDto(Class<D> dtoClass);
/**
* Convert the query to a UpdateQuery.
* <p>
* Typically this is used with query beans to covert a query bean
* query into an UpdateQuery like the examples below.
* </p>
*
* <pre>{@code
*
* int rowsUpdated = new QCustomer()
* .name.startsWith("Rob")
* .asUpdate()
* .set("active", false)
* .update();;
*
* }</pre>
*
* <pre>{@code
*
* int rowsUpdated = new QContact()
* .notes.note.startsWith("Make Inactive")
* .email.endsWith("@foo.com")
* .customer.id.equalTo(42)
* .asUpdate()
* .set("inactive", true)
* .setRaw("email = lower(email)")
* .update();
*
* }</pre>
*/
UpdateQuery<T> asUpdate();
/**
* Cancel the query execution if supported by the underlying database and
* driver.
@@ -340,6 +354,27 @@ public interface Query<T> {
*/
Query<T> setAutoTune(boolean autoTune);
/**
* Execute the query allowing properties with invalid JSON to be collected and not fail the query.
* <pre>{@code
*
* // fetch a bean with JSON content
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
* .setId(42)
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
* .findOne();
*
*
* // get the invalid JSON errors from the bean state
* Map<String, Exception> errors = server().getBeanState(bean).getLoadErrors();
*
* // If this map is not empty tell we have invalid JSON
* // and should try and fix the JSON content or inform the user
*
* }</pre>
*/
Query<T> setAllowLoadErrors();
/**
* Set the default lazy loading batch size to use.
* <p>
@@ -383,8 +418,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* // Only fetch the customer id, name and status.
* // This is described as a "Partial Object"
* .select("name, status")
@@ -412,8 +446,7 @@ public interface Query<T> {
* <pre>{@code
*
* // query orders...
* List<Order> orders =
* ebeanServer.find(Order.class)
* List<Order> orders = DB.find(Order.class)
* // fetch the customer...
* // ... getting the customers name and phone number
* .fetch("customer", "name, phoneNumber")
@@ -428,8 +461,7 @@ public interface Query<T> {
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email")
* .findList();
@@ -498,8 +530,7 @@ public interface Query<T> {
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
* .findList();
@@ -520,8 +551,7 @@ public interface Query<T> {
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* // eager fetch the contacts
* .fetch("contacts")
* .findList();
@@ -584,8 +614,7 @@ public interface Query<T> {
* <pre>{@code
*
* // fetch customers (their id, name and status)
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* // lazy fetch contacts with a batch size of 100
* .fetch("contacts", new FetchConfig().lazy(100))
* .findList();
@@ -605,7 +634,7 @@ public interface Query<T> {
/**
* Execute the query returning the list of Id's.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* This query will execute against the Database that was used to create it.
* </p>
*/
@Nonnull
@@ -627,24 +656,21 @@ public interface Query<T> {
* the jdbc statement and resultSet are closed at the end of the iteration.
* </p>
* <p>
* This query will execute against the EbeanServer that was used to create it.
* This query will execute against the Database that was used to create it.
* </p>
* <pre>{@code
*
* Query<Customer> query =
* ebeanServer.find(Customer.class)
* Query<Customer> query = DB.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* // use try with resources to ensure QueryIterator is closed
*
* try (QueryIterator<Customer> it = query.findIterate()) {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
@@ -681,7 +707,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* ebeanServer.find(Customer.class)
* DB.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id")
* .findEach((Customer customer) -> {
@@ -710,7 +736,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* ebeanServer.find(Customer.class)
* DB.find(Customer.class)
* .fetch("contacts", new FetchConfig().query(2))
* .where().eq("status", Status.NEW)
* .order().asc("id")
@@ -733,12 +759,11 @@ public interface Query<T> {
/**
* Execute the query returning the list of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* This query will execute against the Database that was used to create it.
* </p>
* <pre>{@code
*
* List<Customer> customers =
* ebeanServer.find(Customer.class)
* List<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findList();
*
@@ -750,12 +775,11 @@ public interface Query<T> {
/**
* Execute the query returning the set of objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* This query will execute against the Database that was used to create it.
* </p>
* <pre>{@code
*
* Set<Customer> customers =
* ebeanServer.find(Customer.class)
* Set<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findSet();
*
@@ -767,7 +791,7 @@ public interface Query<T> {
/**
* Execute the query returning a map of the objects.
* <p>
* This query will execute against the EbeanServer that was used to create it.
* This query will execute against the Database that was used to create it.
* </p>
* <p>
* You can use setMapKey() so specify the property values to be used as keys
@@ -775,8 +799,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* Map<String, Product> map =
* ebeanServer.find(Product.class)
* Map<String, Product> map = DB.find(Product.class)
* .setMapKey("sku")
* .findMap();
*
@@ -792,7 +815,7 @@ public interface Query<T> {
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
@@ -803,7 +826,7 @@ public interface Query<T> {
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
@@ -824,7 +847,7 @@ public interface Query<T> {
* <pre>{@code
*
* String name =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
@@ -838,6 +861,37 @@ public interface Query<T> {
*/
boolean isCountDistinct();
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists =
* new QContact()
* .email.equalTo("rob@foo.com")
* .exists();
*
* }</pre>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query()
* .where().eq("email", "rob@foo.com")
* .exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
@@ -852,8 +906,7 @@ public interface Query<T> {
* <pre>{@code
*
* // assuming the sku of products is unique...
* Product product =
* ebeanServer.find(Product.class)
* Product product = DB.find(Product.class)
* .where().eq("sku", "aa113")
* .findOne();
* ...
@@ -865,8 +918,7 @@ public interface Query<T> {
* <pre>{@code
*
* // Fetch order 1 and additionally fetch join its order details...
* Order order =
* ebeanServer.find(Order.class)
* Order order = DB.find(Order.class)
* .setId(1)
* .fetch("details")
* .findOne();
@@ -924,11 +976,31 @@ public interface Query<T> {
*/
int delete();
/**
* Execute as a delete query returning the number of rows deleted using the given transaction.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @return the number of beans/rows that were deleted.
*/
int delete(Transaction transaction);
/**
* Execute the UpdateQuery returning the number of rows updated.
*
* @return the number of beans/rows updated.
*/
int update();
/**
* Execute the UpdateQuery returning the number of rows updated using the given transaction.
*
* @return the number of beans/rows updated.
*/
int update(Transaction transaction);
/**
* Return the count of entities this query should return.
* <p>
@@ -987,7 +1059,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* PagedList<Order> pagedList = Ebean.find(Order.class)
* PagedList<Order> pagedList = DB.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
@@ -1012,11 +1084,9 @@ public interface Query<T> {
* // a query with a named parameter
* String oql = "find order where status = :orderStatus";
*
* Query<Order> query = ebeanServer.find(Order.class, oql);
*
* // bind the named parameter
* query.bind("orderStatus", OrderStatus.NEW);
* List<Order> list = query.findList();
* List<Order> list = DB.find(Order.class, oql)
* .setParameter("orderStatus", OrderStatus.NEW)
* .findList();
*
* }</pre>
*
@@ -1034,12 +1104,9 @@ public interface Query<T> {
* // a query with a positioned parameter
* String oql = "where status = ? order by id desc";
*
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
*
* // bind the parameter
* query.setParameter(1, OrderStatus.NEW);
*
* List<Order> list = query.findList();
* List<Order> list = DB.createQuery(Order.class, oql)
* .setParameter(1, OrderStatus.NEW)
* .findList();
*
* }</pre>
*
@@ -1056,8 +1123,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* Order order =
* ebeanServer.find(Order.class)
* Order order = DB.find(Order.class)
* .setId(1)
* .fetch("details")
* .findOne();
@@ -1078,8 +1144,7 @@ public interface Query<T> {
* Add a single Expression to the where clause returning the query.
* <pre>{@code
*
* List<Order> newOrders =
* ebeanServer.find(Order.class)
* List<Order> newOrders = DB.find(Order.class)
* .where().eq("status", Order.NEW)
* .findList();
* ...
@@ -1094,8 +1159,7 @@ public interface Query<T> {
* where clause.
* <pre>{@code
*
* List<Order> orders =
* ebeanServer.find(Order.class)
* List<Order> orders = DB.find(Order.class)
* .where()
* .eq("status", Order.NEW)
* .ilike("customer.name","rob%")
@@ -1141,10 +1205,7 @@ public interface Query<T> {
* </p>
* <pre>{@code
*
* List<Customer> list =
* ebeanServer.find(Customer.class)
* // .fetch("orders", new FetchConfig().lazy())
* // .fetch("orders", new FetchConfig().query())
* List<Customer> list = DB.find(Customer.class)
* .fetch("orders")
* .where().ilike("name", "rob%")
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
@@ -1158,8 +1219,7 @@ public interface Query<T> {
* </p>
*
* @param propertyName the name of the many property that you want to have a filter on.
* @return the expression list that you add filter expressions for the many
* to.
* @return the expression list that you add filter expressions for the many to.
*/
ExpressionList<T> filterMany(String propertyName);
@@ -1273,7 +1333,7 @@ public interface Query<T> {
* <pre>{@code
*
* List<Customer> customers =
* Ebean.find(Customer.class)
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .findList();
@@ -1289,7 +1349,7 @@ public interface Query<T> {
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* Ebean.find(Order.class)
* DB.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
@@ -1309,7 +1369,6 @@ public interface Query<T> {
* count:1 orderStatus:COMPLETE
*
* }</pre>
*
*/
Query<T> setCountDistinct(CountDistinctOrder orderBy);
@@ -1346,10 +1405,8 @@ public interface Query<T> {
*
* // Assuming sku is unique for products...
*
* Map<String,Product> productMap =
* ebeanServer.find(Product.class)
* // use sku for keys...
* .setMapKey("sku")
* Map<String,Product> productMap = DB.find(Product.class)
* .setMapKey("sku") // sku map keys...
* .findMap();
*
* }</pre>
@@ -1485,15 +1542,6 @@ public interface Query<T> {
*/
String getGeneratedSql();
/**
* Deprecated - migrate to forUpdate().
*
* executed the select with "for update" which should lock the record
* "on read"
*/
@Deprecated
Query<T> setForUpdate(boolean forUpdate);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
@@ -1530,11 +1578,50 @@ public interface Query<T> {
*/
Query<T> alias(String alias);
/**
* Set the base table to use for this query.
* <p>
* Typically this is used when a table has partitioning and we wish to specify a specific
* partition/table to query against.
* </p>
* <pre>{@code
*
* QOrder()
* .setBaseTable("order_2019_05")
* .status.equalTo(Status.NEW)
* .findList();
*
* }</pre>
*/
Query<T> setBaseTable(String baseTable);
/**
* Return the type of beans being queried.
*/
Class<T> getBeanType();
/**
* Restrict the query to only return subtypes of the given inherit type.
*
* <pre>{@code
*
* List<Animal> animals =
* new QAnimal()
* .name.startsWith("Fluffy")
* .setInheritType(Cat.class)
* .findList();
*
* }</pre>
*
* @param type An inheritance subtype of the
*/
Query<T> setInheritType(Class<? extends T> type);
/**
* Returns the inherit type. This is normally the same as getBeanType() returns as long as no other type is set.
*/
Class<? extends T> getInheritType();
/**
* Return the type of query being executed.
*/
+3 -3
View File
@@ -87,7 +87,7 @@ package io.ebean;
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
* .create();
*
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
* List<OrderAggregate> list = DB.find(OrderAggregate.class)
* .setRawSql(rawSql)
* .where().gt("order.id", 0)
* .having().gt("totalAmount", 20)
@@ -114,7 +114,7 @@ package io.ebean;
* .columnMappingIgnore("'ignoreMe'")
* .create();
*
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
* .setRawSql(rawSql)
* .fetch("order", "status,orderDate", new FetchConfig().query())
* .fetch("order.customer", "name")
@@ -146,7 +146,7 @@ package io.ebean;
* .tableAliasMapping("p", "details.product")
* .create();
*
* List<Order> ordersFromRaw = Ebean.find(Order.class)
* List<Order> ordersFromRaw = DB.find(Order.class)
* .setRawSql(rawSql)
* .setParameter("maxOrderId", 2)
* .setParameter("productId", 1)
+1 -1
View File
@@ -13,7 +13,7 @@ import java.sql.SQLException;
*
* String sql = "select id, name, status from o_customer order by name desc";
*
* Ebean.createSqlQuery(sql)
* DB.sqlQuery(sql)
* .findEachRow((resultSet, rowNum) -> {
*
* // read directly from ResultSet
+1 -1
View File
@@ -40,7 +40,7 @@ import java.sql.SQLException;
*
* String sql = "select id, name, status from o_customer where name = ?";
*
* CustomerDto rob = Ebean.createSqlQuery(sql)
* CustomerDto rob = DB.sqlQuery(sql)
* .setParameter(1, "Rob")
* .findOne(CUSTOMER_MAPPER);
*
+53
View File
@@ -0,0 +1,53 @@
package io.ebean;
import java.net.URL;
import java.util.Map;
/**
* Runs DDL and SQL scripts.
* <p/>
* Typically these are scripts used for testing such as seed SQL scripts or truncate SQL scripts.
* <p/>
* Scripts are executed in their own transaction and committed on successful completion.
*
* <h3>Example of simple use</h3>
* <pre>{@code
*
* Database database = DB.getDefault();
* database.script().run("/scripts/test-script.sql");
*
* }</pre>
*/
public interface ScriptRunner {
/**
* Run a script given the resource path (that should start with "/").
*/
void run(String path);
/**
* Run a script given the resource path (that should start with "/") and place holders.
*
* <pre>{@code
*
* Map<String,String> placeholders = new HashMap<>();
* placeholders.put("tableName", "e_basic");
*
* Database database = DB.getDefault();
* database.script().run("/scripts/test-script.sql", placeholders);
*
* }</pre>
*/
void run(String path, Map<String, String> placeholderMap);
/**
* Run a DDL or SQL script given the resource.
*/
void run(URL resource);
/**
* Run a DDL or SQL script given the resource and place holders.
*/
void run(URL resource, Map<String, String> placeholderMap);
}
+47 -23
View File
@@ -10,34 +10,30 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Query object for performing native SQL queries that return SqlRow's.
* <p>
* Firstly note that you can use your own sql queries with <em>entity beans</em>
* by using the SqlSelect annotation. This should be your first approach when
* wanting to use your own SQL queries.
* </p>
* <p>
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
* could be a good approach.
* </p>
* Query object for performing native SQL queries that return SqlRow or directly read
* ResultSet using a RowMapper.
* <p>
* The returned SqlRow objects are similar to a LinkedHashMap with some type
* conversion support added.
* </p>
* <p>
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
* </p>
* <p>
* Refer to {@link Database#findNative(Class, String)} for native sql queries returning entity beans.
* </p>
*
* <pre>{@code
*
* // its typically a good idea to use a named query
* // and put the sql in the orm.xml instead of in your code
* // example using named parameters
*
* String sql = "select id, name from customer where name like :name and status_code = :status";
*
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
* sqlQuery.setParameter("name", "Acme%");
* sqlQuery.setParameter("status", "ACTIVE");
*
* // execute the query returning a List of MapBean objects
* List<SqlRow> list = sqlQuery.findList();
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParameter("name", "Acme%")
* .setParameter("status", "ACTIVE")
* .findList();
*
* }</pre>
*/
@@ -104,7 +100,7 @@ public interface SqlQuery extends Serializable {
*
* String sql = "select id, name, status from customer order by name desc";
*
* Ebean.createSqlQuery(sql)
* DB.sqlQuery(sql)
* .findEachRow((resultSet, rowNum) -> {
*
* // read directly from ResultSet
@@ -134,7 +130,7 @@ public interface SqlQuery extends Serializable {
*
* String sql = "select max(unit_price) from o_order_detail where order_qty > ?";
*
* BigDecimal maxPrice = Ebean.createSqlQuery(sql)
* BigDecimal maxPrice = DB.sqlQuery(sql)
* .setParameter(1, 2)
* .findSingleAttribute(BigDecimal.class);
*
@@ -176,9 +172,10 @@ public interface SqlQuery extends Serializable {
* " order by (unit_price * order_qty) desc";
*
* //
* List<BigDecimal> lineAmounts = Ebean.createSqlQuery(sql)
* .setParameter(1, 3)
* .findSingleAttributeList(BigDecimal.class);
* List<BigDecimal> lineAmounts =
* DB.sqlQuery(sql)
* .setParameter(1, 3)
* .findSingleAttributeList(BigDecimal.class);
*
* }</pre>
*
@@ -195,6 +192,33 @@ public interface SqlQuery extends Serializable {
*/
SqlQuery setParameter(String name, Object value);
/**
* Set one of more positioned parameters.
* <p>
* This is a convenient alternative to multiple calls setParameter().
*
* <pre>{@code
*
* String sql = "select id, name from customer where name like ? and status = ?";
*
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParams("Rob", Status.NEW)
* .findList();
*
*
* // is the same as ...
*
* List<SqlRow> list =
* DB.sqlQuery(sql)
* .setParameter(1, "Rob")
* .setParameter(2, "Status.NEW)
* .findList();
*
* }</pre>
*/
SqlQuery setParams(Object... values);
/**
* The same as bind for positioned parameters.
*/
+62 -11
View File
@@ -16,20 +16,33 @@ package io.ebean;
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
* server cache.
* </p>
* <p>
*
* <pre>{@code
*
* // example that uses 'named' parameters
* // example using 'positioned' parameters
*
* String s = "UPDATE f_topic set post_count = :count where id = :id";
* String sql = "insert into audit_log (group, title, description) values (?, ?, ?);
*
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter("id", 1);
* update.setParameter("count", 50);
* int rows =
* DB.sqlUpdate(sql)
* .setParams("login", "new user", "user rob was created")
* .executeNow();
*
* int modifiedCount = update.execute();
* }</pre>
*
* String msg = "There were " + modifiedCount + " rows updated";
* <pre>{@code
*
* // example using 'named' parameters
*
* String sql = "update topic set post_count = :count where id = :id";
*
* int rows =
* DB.sqlUpdate(sql)
* .setParameter("id", 1)
* .setParameter("count", 50)
* .execute();
*
* String msg = "There were " + rows + " rows updated";
*
* }</pre>
* <p>
@@ -37,9 +50,10 @@ package io.ebean;
* <pre>{@code
*
* String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
* SqlUpdate insert = Ebean.createSqlUpdate(sql);
*
* try (Transaction txn = Ebean.beginTransaction()) {
* SqlUpdate insert = DB.sqlUpdate(sql);
*
* try (Transaction txn = DB.beginTransaction()) {
* txn.setBatchMode(true);
*
* insert.setNextParameter(10000);
@@ -65,7 +79,7 @@ package io.ebean;
* </p>
* <pre>{@code
*
* try (Transaction txn = Ebean.beginTransaction()) {
* try (Transaction txn = DB.beginTransaction()) {
*
* insert.setNextParameter(10000);
* insert.setNextParameter("hello");
@@ -98,6 +112,11 @@ public interface SqlUpdate {
/**
* Execute the update returning the number of rows modified.
* <p>
* Note that if the transaction has batch mode on then this update will use JDBC batch and may not execute until
* later - at commit time or a transaction flush. In this case this method returns -1 indicating that the
* update has been batched for later execution.
* </p>
* <p>
* After you have executed the SqlUpdate you can bind new variables using
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
* again.
@@ -112,6 +131,11 @@ public interface SqlUpdate {
*/
int execute();
/**
* Execute the statement now regardless of the JDBC batch mode of the transaction.
*/
int executeNow();
/**
* Execute when addBatch() has been used to batch multiple bind executions.
*
@@ -207,6 +231,33 @@ public interface SqlUpdate {
*/
SqlUpdate setTimeout(int secs);
/**
* Set one of more positioned parameters.
* <p>
* This is a convenient alternative to multiple setParameter() calls.
*
* <pre>{@code
*
* String sql = "insert into audit_log (id, name, version) values (?,?,?)";
*
* DB.sqlUpdate(sql)
* .setParams(UUID.randomUUID(), "Hello", 1)
* .executeNow();
*
*
* // is the same as ...
*
* DB.sqlUpdate(sql)
* .setParameter(1, UUID.randomUUID())
* .setParameter(2, "Hello")
* .setParameter(3, 1)
* .executeNow();
*
* }</pre>
*
*/
SqlUpdate setParams(Object... values);
/**
* Set the next positioned parameter.
*
+71 -86
View File
@@ -14,18 +14,17 @@ import java.sql.Connection;
public interface Transaction extends AutoCloseable {
/**
* Return the current transaction (of the default server) or null if there is
* Return the current transaction (of the default database) or null if there is
* no current transaction in scope.
* <p>
* This is the same as <code>Ebean.currentTransaction()</code>
* This is the same as <code>DB.currentTransaction()</code>
* </p>
* <p>
* This returns the current transaction for the 'default server'. If you are using
* multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}.
* This returns the current transaction for the default database.
* </p>
*
* @see Ebean#currentTransaction()
* @see EbeanServer#currentTransaction()
* @see DB#currentTransaction()
* @see Database#currentTransaction()
*/
static Transaction current() {
return Ebean.currentTransaction();
@@ -84,7 +83,7 @@ public interface Transaction extends AutoCloseable {
* <p>
* This is similar to commit() but leaves the transaction "Active".
* </p>
* <h3>Functions/h3>
* <h3>Functions</h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
@@ -100,7 +99,7 @@ public interface Transaction extends AutoCloseable {
* This performs commit and completes the transaction closing underlying resources and
* marking the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <h3>Functions</h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
@@ -117,7 +116,7 @@ public interface Transaction extends AutoCloseable {
* <p>
* This performs rollback, closes underlying resources and marks the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <h3>Functions</h3>
* <ul>
* <li>Call rollback on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
@@ -244,8 +243,7 @@ public interface Transaction extends AutoCloseable {
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
* try (Transaction transaction = DB.beginTransaction()) {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
@@ -253,7 +251,7 @@ public interface Transaction extends AutoCloseable {
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
* someBean.save();
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
@@ -273,8 +271,7 @@ public interface Transaction extends AutoCloseable {
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* transaction.commit();
* }
*
* }</pre>
@@ -290,36 +287,66 @@ public interface Transaction extends AutoCloseable {
boolean isSkipCache();
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
* wish to specifically control when batching is used via this method.
* <p>
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
* <p>
* Note that you may also wish to use the setPersistCascade method to stop
* save and delete cascade behaviour. You may do this to have full control
* over the order of execution rather than the normal cascading fashion.
* </p>
* <p>
* Note that the <em>execution order</em> in batch mode may be different from
* non batch mode execution order. Also note that <em>insert behaviour</em>
* may be different depending on the JDBC driver and its support for
* getGeneratedKeys. That is, for JDBC drivers that do not support
* getGeneratedKeys you may not get back the generated IDs (used for inserting
* associated detail beans etc).
* </p>
* Turn on or off use of JDBC statement batching.
* <p>
* Calls to save(), delete(), insert() and execute() all support batch
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
* processing. This includes normal beans, CallableSql and UpdateSql.
* </p>
*
* <pre>{@code
*
* try (Transaction transaction = server.beginTransaction()) {
*
* // turn on JDBC batch
* transaction.setBatchMode(true);
*
* // tune the batch size
* transaction.setBatchSize(50);
*
* ...
*
* transaction.commit();
* }
*
* }</pre>
*
* <h3>getGeneratedKeys</h3>
* <p>
* The flushing of the batched statements is automatic but you can call
* batchFlush when you like. Note that flushing occurs when a query is
* executed or when you mix UpdateSql and CallableSql with save and delete of
* Often with large batch inserts we want to turn off getGeneratedKeys. We do
* this via {@link #setBatchGetGeneratedKeys(boolean)}.
* Also note that some JDBC drivers do not support getGeneratedKeys in JDBC batch mode.
* </p>
* <pre>{@code
*
* try (Transaction transaction = server.beginTransaction()) {
*
* transaction.setBatchMode(true);
* transaction.setBatchSize(100);
* // insert but don't bother getting back the generated keys
* transaction.setBatchGetGeneratedKeys(false);
*
*
* // perform lots of inserts ...
* ...
*
* transaction.commit();
* }
*
* }</pre>
*
* <h3>Flush</h3>
* <p>
* The batch is automatically flushed when it hits the batch size and also when we
* execute queries or when we mix UpdateSql and CallableSql with save and delete of
* beans.
* </p>
* <p>
* Example: batch processing executing every 3 rows
* We use {@link #flush()} to explicitly flush the batch and we can use
* {@link #setBatchFlushOnQuery(boolean)} and {@link #setBatchFlushOnMixed(boolean)}
* to control the automatic flushing behaviour.
* </p>
* <p>
* Example: batch processing of CallableSql executing every 10 rows
* </p>
*
* <pre>{@code
@@ -334,53 +361,27 @@ public interface Transaction extends AutoCloseable {
* CallableSql cs = new CallableSql(sql);
* cs.registerOut(2, Types.INTEGER);
*
* // (optional) inform eBean this stored procedure
* // (optional) inform Ebean this stored procedure
* // inserts into a table called sp_test
* cs.addModification("sp_test", true, false, false);
*
* Transaction txn = ebeanServer.beginTransaction();
* txn.setBatchMode(true);
* txn.setBatchSize(3);
* try {
* try (Transaction txn = DB.beginTransaction()) {
* txn.setBatchMode(true);
* txn.setBatchSize(10);
*
* for (int i = 0; i < da.length;) {
* cs.setParameter(1, da[i]);
* ebeanServer.execute(cs);
* DB.execute(cs);
* }
*
* // NB: commit implicitly flushes
* // Note: commit implicitly flushes
* txn.commit();
*
* } finally {
* txn.end();
* }
*
* }</pre>
*/
void setBatchMode(boolean useBatch);
/**
* Deprecated - migrate to {@link #setBatchMode(boolean)}.
* <p>
* Set the JDBC batch mode to use for this transaction.
* </p>
* <p>
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
* and this would be useful if the request cascades to detail beans.
* </p>
*
* @param persistBatchMode the batch mode to use for this transaction
* @see io.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
*/
@Deprecated
void setBatch(PersistBatch persistBatchMode);
/**
* Deprecated - migrate to {@link #isBatchMode()}.
* Return the batch mode at the transaction level.
*/
@Deprecated
PersistBatch getBatch();
/**
* Return the batch mode at the transaction level.
*/
@@ -405,22 +406,6 @@ public interface Transaction extends AutoCloseable {
*/
void setBatchOnCascade(boolean batchMode);
/**
* Set the batch mode when cascading.
* <p>
* Deprecated in favour of {@link #setBatchOnCascade(boolean)}
* </p>
*/
@Deprecated
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
/**
* Deprecated - migrate to {@link #isBatchMode()}.
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
*/
@Deprecated
PersistBatch getBatchOnCascade();
/**
* Return the batch mode at the request level.
*/
+7
View File
@@ -432,4 +432,11 @@ public final class TxScope {
return this;
}
public boolean isBatchMode() {
return PersistBatch.ALL.equals(batch);
}
public boolean isBatchOnCascade() {
return PersistBatch.ALL.equals(batchOnCascade);
}
}
+1 -1
View File
@@ -41,7 +41,7 @@ package io.ebean;
* <p>
* <pre>{@code
*
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
* Update<Topic> update = DB.createUpdate(Topic.class, "incrementPostCount");
* update.setParameter("id", 1);
* int rows = update.execute();
*
+16 -12
View File
@@ -12,8 +12,7 @@ package io.ebean;
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
@@ -39,8 +38,7 @@ package io.ebean;
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
@@ -73,8 +71,7 @@ public interface UpdateQuery<T> {
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
@@ -93,8 +90,7 @@ public interface UpdateQuery<T> {
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .setNull("notes")
* .where()
* .gt("id", 1000)
@@ -114,8 +110,7 @@ public interface UpdateQuery<T> {
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .setRaw("status = coalesce(status, 'A')")
* .where()
* .gt("id", 1000)
@@ -134,8 +129,7 @@ public interface UpdateQuery<T> {
* </p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* int rows = DB.update(Customer.class)
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
* .where()
* .gt("id", 1000)
@@ -154,9 +148,19 @@ public interface UpdateQuery<T> {
*/
UpdateQuery<T> setProfileLocation(ProfileLocation profileLocation);
/**
* Set the label on the update query.
*/
UpdateQuery<T> setLabel(String label);
/**
* Return the query expression list to add predicates to.
*/
ExpressionList<T> where();
/**
* Execute the update returning the number of rows updated.
*/
int update();
}
@@ -9,7 +9,7 @@ package io.ebean.bean;
public interface BeanCollectionLoader {
/**
* Return the name of the associated EbeanServer.
* Return the name of the associated Database.
*/
String getName();
+1 -1
View File
@@ -9,7 +9,7 @@ package io.ebean.bean;
public interface BeanLoader {
/**
* Return the name of the associated EbeanServer.
* Return the name of the associated Database.
*/
String getName();
@@ -71,24 +71,35 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Used when a bean is partially filled.
*/
private final boolean[] loadedProps;
private boolean fullyLoadedBean;
private static final byte FLAG_LOADED_PROP = 1;
/**
* Set of changed properties.
*/
private boolean[] changedProps;
private static final byte FLAG_CHANGED_PROP = 2;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distingush
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
private boolean[] embeddedDirty;
private static final byte FLAG_EMBEDDED_DIRTY = 4;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distingush
* 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;
private final byte[] flags;
private boolean fullyLoadedBean;
private Object[] origValues;
private Exception[] loadErrors;
private int lazyLoadProperty = -1;
private Object ownerId;
@@ -102,7 +113,7 @@ public final class EntityBeanIntercept implements Serializable {
*/
public EntityBeanIntercept(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
this.loadedProps = new boolean[owner._ebean_getPropertyNames().length];
this.flags = new byte[owner._ebean_getPropertyNames().length];
}
/**
@@ -213,8 +224,8 @@ public final class EntityBeanIntercept implements Serializable {
* Check each property to see if the bean is partially loaded.
*/
public boolean isPartial() {
for (boolean loadedProp : loadedProps) {
if (!loadedProp) {
for (byte flag : flags) {
if ((flag & FLAG_LOADED_PROP) == 0) {
return true;
}
}
@@ -259,10 +270,10 @@ public final class EntityBeanIntercept implements Serializable {
* Return true if only the Id property has been loaded.
*/
public boolean hasIdOnly(int idIndex) {
for (int i = 0; i < loadedProps.length; i++) {
for (int i = 0; i < flags.length; i++) {
if (i == idIndex) {
if (!loadedProps[i]) return false;
} else if (loadedProps[i]) {
if ((flags[i] & FLAG_LOADED_PROP) == 0) return false;
} else if ((flags[i] & FLAG_LOADED_PROP) != 0) {
return false;
}
}
@@ -284,9 +295,9 @@ public final class EntityBeanIntercept implements Serializable {
if (idPos > -1) {
// For cases where properties are set on constructor
// set every non Id property to unloaded (for lazy loading)
for (int i = 0; i < loadedProps.length; i++) {
for (int i = 0; i < flags.length; i++) {
if (i != idPos) {
loadedProps[i] = false;
flags[i] &= ~FLAG_LOADED_PROP;
}
}
}
@@ -352,7 +363,9 @@ public final class EntityBeanIntercept implements Serializable {
this.owner._ebean_setEmbeddedLoaded();
this.lazyLoadProperty = -1;
this.origValues = null;
this.changedProps = null;
for (int i = 0; i < flags.length; i++) {
flags[i] &= ~(FLAG_CHANGED_PROP + FLAG_ORIG_VALUE_SET);
}
this.dirty = false;
}
@@ -475,7 +488,11 @@ public final class EntityBeanIntercept implements Serializable {
if (position == -1) {
throw new IllegalArgumentException("Property " + propertyName + " not found");
}
loadedProps[position] = loaded;
if (loaded) {
flags[position] |= FLAG_LOADED_PROP;
} else {
flags[position] &= ~FLAG_LOADED_PROP;
}
}
/**
@@ -483,22 +500,22 @@ public final class EntityBeanIntercept implements Serializable {
* constructor.
*/
public void setPropertyUnloaded(int propertyIndex) {
loadedProps[propertyIndex] = false;
flags[propertyIndex] &= ~FLAG_LOADED_PROP;
}
/**
* Set the property to be loaded.
*/
public void setLoadedProperty(int propertyIndex) {
loadedProps[propertyIndex] = true;
flags[propertyIndex] |= FLAG_LOADED_PROP;
}
/**
* Set all properties to be loaded (post insert).
*/
public void setLoadedPropertyAll() {
for (int i = 0; i < loadedProps.length; i++) {
loadedProps[i] = true;
for (int i = 0; i < flags.length; i++) {
flags[i] |= FLAG_LOADED_PROP;
}
}
@@ -506,14 +523,14 @@ public final class EntityBeanIntercept implements Serializable {
* Return true if the property is loaded.
*/
public boolean isLoadedProperty(int propertyIndex) {
return loadedProps[propertyIndex];
return (flags[propertyIndex] & FLAG_LOADED_PROP) != 0;
}
/**
* Return true if the property is considered changed.
*/
public boolean isChangedProperty(int propertyIndex) {
return (changedProps != null && changedProps[propertyIndex]);
return (flags[propertyIndex] & FLAG_CHANGED_PROP) != 0;
}
/**
@@ -521,8 +538,7 @@ public final class EntityBeanIntercept implements Serializable {
* embedded properties is dirty.
*/
public boolean isDirtyProperty(int propertyIndex) {
return (changedProps != null && changedProps[propertyIndex]
|| embeddedDirty != null && embeddedDirty[propertyIndex]);
return (flags[propertyIndex] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0;
}
/**
@@ -534,27 +550,22 @@ public final class EntityBeanIntercept implements Serializable {
}
public void setChangedProperty(int propertyIndex) {
if (changedProps == null) {
changedProps = new boolean[owner._ebean_getPropertyNames().length];
}
changedProps[propertyIndex] = true;
flags[propertyIndex] |= FLAG_CHANGED_PROP;
}
/**
* Set that an embedded bean has had one of its properties changed.
*/
private void setEmbeddedPropertyDirty(int propertyIndex) {
if (embeddedDirty == null) {
embeddedDirty = new boolean[owner._ebean_getPropertyNames().length];
}
embeddedDirty[propertyIndex] = true;
flags[propertyIndex] |= FLAG_EMBEDDED_DIRTY;
}
private void setOriginalValue(int propertyIndex, Object value) {
if (origValues == null) {
origValues = new Object[owner._ebean_getPropertyNames().length];
}
if (origValues[propertyIndex] == null) {
if ((flags[propertyIndex] & FLAG_ORIG_VALUE_SET) == 0) {
flags[propertyIndex] |= FLAG_ORIG_VALUE_SET;
origValues[propertyIndex] = value;
}
}
@@ -574,13 +585,9 @@ public final class EntityBeanIntercept implements Serializable {
*/
public void setNewBeanForUpdate() {
if (changedProps == null) {
changedProps = new boolean[owner._ebean_getPropertyNames().length];
}
for (int i = 0; i < loadedProps.length; i++) {
if (loadedProps[i]) {
changedProps[i] = true;
for (int i = 0; i < flags.length; i++) {
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
flags[i] |= FLAG_CHANGED_PROP;
}
}
setDirty(true);
@@ -594,8 +601,8 @@ public final class EntityBeanIntercept implements Serializable {
return null;
}
Set<String> props = new LinkedHashSet<>();
for (int i = 0; i < loadedProps.length; i++) {
if (loadedProps[i]) {
for (int i = 0; i < flags.length; i++) {
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
props.add(getProperty(i));
}
}
@@ -609,12 +616,8 @@ public final class EntityBeanIntercept implements Serializable {
int len = getPropertyLength();
boolean[] dirties = new boolean[len];
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
dirties[i] = true;
} else if (embeddedDirty != null && embeddedDirty[i]) {
// an embedded property has been changed - recurse
dirties[i] = true;
}
// this, or an embedded property has been changed - recurse
dirties[i] = (flags[i] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0;
}
return dirties;
}
@@ -634,11 +637,11 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyNames(Set<String> props, String prefix) {
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
props.add(propName);
} else if (embeddedDirty != null && embeddedDirty[i]) {
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
embeddedBean._ebean_getIntercept().addDirtyPropertyNames(props, getProperty(i) + ".");
@@ -654,12 +657,12 @@ public final class EntityBeanIntercept implements Serializable {
String[] names = owner._ebean_getPropertyNames();
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
if (propertyNames.contains(names[i])) {
return true;
}
} else if (embeddedDirty != null && embeddedDirty[i]) {
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
if (propertyNames.contains(names[i])) {
return true;
}
@@ -683,15 +686,16 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) {
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i);
if (!areEqual(oldVal, newVal)) {
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
}
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
} else if (embeddedDirty != null && embeddedDirty[i]) {
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i) + ".");
@@ -705,13 +709,15 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
// the property has been changed on this bean
Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i);
visitor.visit(i, newVal, oldVal);
if (!areEqual(oldVal, newVal)) {
visitor.visit(i, newVal, oldVal);
}
} else if (embeddedDirty != null && embeddedDirty[i]) {
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
visitor.visitPush(i);
@@ -739,9 +745,9 @@ public final class EntityBeanIntercept implements Serializable {
}
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
sb.append(i).append(',');
} else if (embeddedDirty != null && embeddedDirty[i]) {
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
sb.append(i).append('[');
@@ -765,15 +771,12 @@ public final class EntityBeanIntercept implements Serializable {
return sb;
}
/**
* Return the set of property names for changed properties.
*/
public boolean[] getChanged() {
return changedProps;
}
public boolean[] getLoaded() {
return loadedProps;
boolean[] ret= new boolean[flags.length];
for (int i = 0; i < ret.length; i++) {
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
}
return ret;
}
/**
@@ -821,14 +824,14 @@ public final class EntityBeanIntercept implements Serializable {
*/
private void loadBeanInternal(int loadProperty, BeanLoader loader) {
if (loadedProps == null || loadedProps[loadProperty]) {
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
// race condition where multiple threads calling preGetter concurrently
return;
}
if (lazyLoadFailure) {
// failed when batch lazy loaded by another bean in the batch
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
throw new EntityNotFoundException("(Lazy) loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted");
}
if (lazyLoadProperty == -1) {
@@ -887,7 +890,7 @@ public final class EntityBeanIntercept implements Serializable {
* Called when a BeanCollection is initialised automatically.
*/
public void initialisedMany(int propertyIndex) {
loadedProps[propertyIndex] = true;
flags[propertyIndex] |= FLAG_LOADED_PROP;
}
private void preGetterCallback(int propertyIndex) {
@@ -1114,4 +1117,36 @@ public final class EntityBeanIntercept implements Serializable {
public void setSortOrder(int sortOrder) {
this.sortOrder = sortOrder;
}
/**
* Set the load error that happened on this property.
*/
public void setLoadError(int propertyIndex, Exception t) {
if (loadErrors == null) {
loadErrors = new Exception[owner._ebean_getPropertyNames().length];
}
loadErrors[propertyIndex] = t;
flags[propertyIndex] |= FLAG_LOADED_PROP;
}
/**
* Returns the loadErrors.
*/
public Map<String, Exception> getLoadErrors() {
if (loadErrors == null) {
return null;
}
Map<String, Exception> ret = null;
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
Exception loadError = loadErrors[i];
if (loadError != null) {
if (ret == null) {
ret = new LinkedHashMap<>();
}
ret.put(getProperty(i), loadError);
}
}
return ret;
}
}
@@ -19,6 +19,11 @@ public class ServerCacheNotification {
this.dependentTables = dependentTables;
}
@Override
public String toString() {
return "ts:" + modifyTimestamp + " tables:" + dependentTables;
}
public long getModifyTimestamp() {
return modifyTimestamp;
}
+33
View File
@@ -12,6 +12,7 @@ public class ServerCacheOptions {
private int maxIdleSecs;
private int maxSecsToLive;
private int trimFrequency;
private boolean nearCache;
/**
* Construct with no set options.
@@ -40,6 +41,14 @@ public class ServerCacheOptions {
this.trimFrequency = cacheTuning.trimFrequency();
}
/**
* Create with nearCache option.
*/
public ServerCacheOptions(boolean nearCache, CacheBeanTuning tuning) {
this(tuning);
this.nearCache = nearCache;
}
/**
* Apply any settings from the default settings that have not already been
* specifically set.
@@ -70,9 +79,33 @@ public class ServerCacheOptions {
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
copy.trimFrequency = trimFrequency;
copy.nearCache = this.nearCache;
return copy;
}
/**
* Return a copy of this object with nearCache option.
*/
public ServerCacheOptions copy(boolean nearCache) {
ServerCacheOptions copy = copy();
copy.nearCache = nearCache;
return copy;
}
/**
* Return true if nearCache was explicitly turned on.
*/
public boolean isNearCache() {
return nearCache;
}
/**
* Turn on nearCache option.
*/
public void setNearCache(boolean nearCache) {
this.nearCache = nearCache;
}
/**
* Return the maximum cache size.
*/
@@ -20,7 +20,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected boolean disableLazyLoad;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
* The Database this is associated with. (used for lazy fetch).
*/
protected transient BeanCollectionLoader loader;
+12 -5
View File
@@ -123,7 +123,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
private void initClear() {
synchronized (this) {
if (map == null) {
if (modifyListening) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
map = new LinkedHashMap<>();
@@ -135,7 +135,11 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
private void init() {
synchronized (this) {
if (map == null) {
lazyLoadCollection(false);
if (disableLazyLoad) {
map = new LinkedHashMap<>();
} else {
lazyLoadCollection(false);
}
}
}
}
@@ -273,14 +277,16 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
checkReadOnly();
init();
if (modifyListening) {
Object oldBean = map.put(key, value);
E oldBean = map.put(key, value);
if (value != oldBean) {
// register the add of the new and the removal of the old
modifyAddition(value);
modifyRemoval(oldBean);
}
return oldBean;
} else {
return map.put(key, value);
}
return map.put(key, value);
}
@Override
@@ -295,8 +301,9 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
modifyRemoval(oldBean);
}
}
} else {
map.putAll(puts);
}
map.putAll(puts);
}
@Override
+7 -3
View File
@@ -116,7 +116,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
private void initClear() {
synchronized (this) {
if (set == null) {
if (modifyListening) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
set = new LinkedHashSet<>();
@@ -128,7 +128,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
private void init() {
synchronized (this) {
if (set == null) {
lazyLoadCollection(true);
if (disableLazyLoad) {
set = new LinkedHashSet<>();
} else {
lazyLoadCollection(true);
}
}
}
}
@@ -377,7 +381,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
throw new IllegalStateException("This collection is in ReadOnly mode");
}
}
@Override
public BeanCollection<E> getShallowCopy() {
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
@@ -1,7 +1,7 @@
package io.ebean.config;
/**
* Used to provide some automatic configuration early in the creation of an EbeanServer.
* Used to provide some automatic configuration early in the creation of a Database.
*/
public interface AutoConfigure {
@@ -1,11 +1,11 @@
package io.ebean.config;
/**
* Defines the AutoTune behaviour for a EbeanServer.
* Defines the AutoTune behaviour for a Database.
*/
public class AutoTuneConfig {
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
private AutoTuneMode mode = AutoTuneMode.DEFAULT_OFF;
private String queryTuningFile = "ebean-autotune.xml";
@@ -0,0 +1,15 @@
package io.ebean.config;
/**
* Throw when an processing an entity bean that is not bytecode enhanced.
*
* Refer: https://ebean.io/docs/trouble-shooting#not-enhanced
*/
public class BeanNotEnhancedException extends IllegalStateException {
private static final long serialVersionUID = 3008101919425876799L;
public BeanNotEnhancedException(String msg) {
super(msg);
}
}
@@ -0,0 +1,15 @@
package io.ebean.config;
/**
* Throw when an processing thinks a bean is not registered.
*
* Refer: https://ebean.io/docs/trouble-shooting#not-registered
*/
public class BeanNotRegisteredException extends IllegalStateException {
private static final long serialVersionUID = -1411298126011136552L;
public BeanNotRegisteredException(String msg) {
super(msg);
}
}
@@ -3,7 +3,7 @@ package io.ebean.config;
import java.util.Properties;
/**
* Configuration for the container that holds the EbeanServer instances.
* Configuration for the container that holds the Database instances.
* <p>
* Provides configuration for cluster communication (if clustering is used). The cluster communication is
* used to invalidate appropriate parts of the L2 cache across the cluster.
@@ -0,0 +1,44 @@
package io.ebean.config;
import io.ebean.DatabaseFactory;
/**
* The configuration used for creating a Database.
* <p>
* Used to programmatically construct an Database and optionally register it
* with the DB singleton.
* </p>
* <p>
* If you just use DB thout this programmatic configuration Ebean will read
* the application.properties file and take the configuration from there. This usually
* includes searching the class path and automatically registering any entity
* classes and listeners etc.
* </p>
* <pre>{@code
*
* DatabaseConfig config = new DatabaseConfig();
*
* // read the ebean.properties and load
* // those settings into this serverConfig object
* config.loadFromProperties();
*
* // explicitly register the entity beans to avoid classpath scanning
* config.addClass(Customer.class);
* config.addClass(User.class);
*
* Database db = DatabaseFactory.create(config);
*
* }</pre>
*
* <p>
* Note that ServerConfigProvider provides a standard Java ServiceLoader mechanism that can
* be used to apply configuration to the DatabaseConfig.
* </p>
*
* @author emcgreal
* @author rbygrave
* @see DatabaseFactory
*/
public class DatabaseConfig extends ServerConfig {
}
@@ -5,7 +5,6 @@ import io.ebean.annotation.Platform;
import io.ebean.migration.MigrationConfig;
import io.ebean.migration.MigrationRunner;
import io.ebean.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,39 +27,13 @@ public class DbMigrationConfig {
*/
protected Platform platform;
/**
* Set to true if the DB migration should be generated on server start.
*/
protected boolean generate;
/**
* The migration version name (typically FlywayDb compatible).
* <p>
* Example: 1.1.1_2
* <p>
* The version is expected to be the combination of the current pom version plus
* a 'feature' id. The combined version must be unique and ordered to work with
* FlywayDb so each developer sets a unique version so that the migration script
* generated is unique (typically just prior to being submitted as a merge request).
*/
protected String version;
/**
* Description text that can be appended to the version to become the ddl script file name.
* <p>
* So if the name is "a foo table" then the ddl script file could be:
* "1.1.1_2__a-foo-table.sql"
* <p>
* When the DB migration relates to a git feature (merge request) then this description text
* is a short description of the feature.
*/
protected String name;
/**
* Resource path for the migration xml and sql.
*/
protected String migrationPath = "dbmigration";
protected String migrationInitPath = "dbinit";
/**
* Subdirectory the model xml files go into.
*/
@@ -75,13 +48,6 @@ public class DbMigrationConfig {
protected String modelSuffix = ".model.xml";
protected boolean includeGeneratedFileComment;
/**
* The version of a pending drop that should be generated as the next migration.
*/
protected String generatePendingDrop;
/**
* For running migration the DB table that holds migration execution status.
*/
@@ -153,6 +119,15 @@ public class DbMigrationConfig {
this.platform = platform;
}
/**
* Return the path for normal migrations or dbinit migrations.
*
* @param dbinitMigration When true return the path for dbinit migrations.
*/
public String getMigrationPath(boolean dbinitMigration) {
return dbinitMigration ? migrationInitPath : migrationPath;
}
/**
* Return the resource path for db migrations.
*/
@@ -165,7 +140,7 @@ public class DbMigrationConfig {
* <p>
* The default of "dbmigration" is reasonable in most cases. You may look to set this
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
* in the case there are multiple EbeanServer applications in the single classpath.
* in the case there are multiple Database applications in the single classpath.
* </p>
*/
public void setMigrationPath(String migrationPath) {
@@ -228,52 +203,6 @@ public class DbMigrationConfig {
this.applyPrefix = applyPrefix;
}
/**
* Return true if the generated file comment should be included.
*/
public boolean isIncludeGeneratedFileComment() {
return includeGeneratedFileComment;
}
/**
* Set to true if the generated file comment should be included.
*/
public void setIncludeGeneratedFileComment(boolean includeGeneratedFileComment) {
this.includeGeneratedFileComment = includeGeneratedFileComment;
}
/**
* Return the migration version (or "next") to generate pending drops for.
*/
public String getGeneratePendingDrop() {
return generatePendingDrop;
}
/**
* Set the migration version (or "next") to generate pending drops for.
*/
public void setGeneratePendingDrop(String generatePendingDrop) {
this.generatePendingDrop = generatePendingDrop;
}
/**
* Set the migration version.
* <p>
* Note that version set via System property or environment variable <code>ddl.migration.version</code> takes precedence.
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Set the migration name.
* <p>
* Note that name set via System property or environment variable <code>ddl.migration.name</code> takes precedence.
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the table name that holds the migration run details
* (used by DB Migration runner only).
@@ -500,18 +429,13 @@ public class DbMigrationConfig {
public void loadSettings(PropertiesWrapper properties, String serverName) {
migrationPath = properties.get("migration.migrationPath", migrationPath);
migrationInitPath = properties.get("migration.migrationInitPath", migrationInitPath);
modelPath = properties.get("migration.modelPath", modelPath);
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
applySuffix = properties.get("migration.applySuffix", applySuffix);
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
platform = properties.getEnum(Platform.class, "migration.platform", platform);
generate = properties.getBoolean("migration.generate", generate);
version = properties.get("migration.version", version);
name = properties.get("migration.name", name);
patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn);
patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn);
@@ -532,44 +456,6 @@ public class DbMigrationConfig {
ddlHeader = properties.get("ddl.header", ddlHeader);
}
/**
* Return the migration version (typically FlywayDb compatible).
* <p>
* Example: 1.1.1_2
* <p>
* The version is expected to be the combination of the current pom version plus
* a 'feature' id. The combined version must be unique and ordered to work with
* FlywayDb so each developer sets a unique version so that the migration script
* generated is unique (typically just prior to being submitted as a merge request).
*/
public String getVersion() {
String envVersion = readEnvironment("ddl.migration.version");
if (!isEmpty(envVersion)) {
return envVersion.trim();
}
return version;
}
/**
* Return the migration name which is short description text that can be appended to
* the migration version to become the ddl script file name.
* <p>
* So if the name is "a foo table" then the ddl script file could be:
* "1.1.1_2__a-foo-table.sql"
* </p>
* <p>
* When the DB migration relates to a git feature (merge request) then this description text
* is a short description of the feature.
* </p>
*/
public String getName() {
String envName = readEnvironment("ddl.migration.name");
if (!isEmpty(envName)) {
return envName.trim();
}
return name;
}
/**
* Return the system or environment property.
*/
@@ -597,6 +483,7 @@ public class DbMigrationConfig {
runnerConfig.setMetaTable(metaTable);
runnerConfig.setApplySuffix(applySuffix);
runnerConfig.setMigrationPath(migrationPath);
runnerConfig.setMigrationInitPath(migrationInitPath);
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
runnerConfig.setRunPlaceholders(runPlaceholders);
runnerConfig.setDbUsername(getDbUsername());
@@ -47,6 +47,11 @@ public class PlatformConfig {
*/
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
/**
* Set to true to force InetAddress to map to Varchar (for Postgres rather than INET)
*/
private boolean databaseInetAddressVarchar;
/**
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
*/
@@ -181,6 +186,20 @@ public class PlatformConfig {
this.idType = idType;
}
/**
* Return true if InetAddress should map to varchar column (rather than Postgres INET).
*/
public boolean isDatabaseInetAddressVarchar() {
return databaseInetAddressVarchar;
}
/**
* Set to true to force InetAddress to map to varchar column.
*/
public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) {
this.databaseInetAddressVarchar = databaseInetAddressVarchar;
}
/**
* Add a custom type mapping.
* <p>
@@ -235,6 +254,7 @@ public class PlatformConfig {
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
if (dbUuid != null) {
+196 -56
View File
@@ -1,7 +1,7 @@
package io.ebean.config;
import com.fasterxml.jackson.core.JsonFactory;
import io.ebean.EbeanServerFactory;
import io.ebean.DatabaseFactory;
import io.ebean.PersistenceContextScope;
import io.ebean.Query;
import io.ebean.Transaction;
@@ -14,6 +14,7 @@ import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.properties.PropertiesLoader;
import io.ebean.datasource.DataSourceConfig;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
@@ -30,8 +31,8 @@ import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetaInfoManager;
import io.ebean.migration.MigrationRunner;
import io.ebean.util.StringHelper;
import org.avaje.datasource.DataSourceConfig;
import javax.persistence.EnumType;
import javax.sql.DataSource;
import java.time.Clock;
import java.util.ArrayList;
@@ -44,30 +45,30 @@ import java.util.Properties;
import java.util.ServiceLoader;
/**
* The configuration used for creating a EbeanServer.
* The configuration used for creating a Database.
* <p>
* Used to programmatically construct an EbeanServer and optionally register it
* with the Ebean singleton.
* Used to programmatically construct a Database and optionally register it
* with the DB singleton.
* </p>
* <p>
* If you just use Ebean without this programmatic configuration Ebean will read
* the ebean.properties file and take the configuration from there. This usually
* If you just use DB without this programmatic configuration DB will read
* the application.properties file and take the configuration from there. This usually
* includes searching the class path and automatically registering any entity
* classes and listeners etc.
* </p>
* <pre>{@code
*
* ServerConfig c = new ServerConfig();
* ServerConfig config = new ServerConfig();
*
* // read the ebean.properties and load
* // those settings into this serverConfig object
* c.loadFromProperties();
* config.loadFromProperties();
*
* // explicitly register the entity beans to avoid classpath scanning
* c.addClass(Customer.class);
* c.addClass(User.class);
* config.addClass(Customer.class);
* config.addClass(User.class);
*
* EbeanServer server = EbeanServerFactory.create(c);
* Database database = DatabaseFactory.create(config);
*
* }</pre>
*
@@ -78,12 +79,12 @@ import java.util.ServiceLoader;
*
* @author emcgreal
* @author rbygrave
* @see EbeanServerFactory
* @see DatabaseFactory
*/
public class ServerConfig {
/**
* The EbeanServer name.
* The Database name.
*/
private String name = "db";
@@ -106,12 +107,12 @@ public class ServerConfig {
private String resourceDirectory;
/**
* Set to true to register this EbeanServer with the Ebean singleton.
* Set to true to register this Database with the DB singleton.
*/
private boolean register = true;
/**
* Set to true if this is the default/primary server.
* Set to true if this is the default/primary database.
*/
private boolean defaultServer = true;
@@ -150,7 +151,7 @@ public class ServerConfig {
private DocStoreConfig docStoreConfig = new DocStoreConfig();
/**
* Set to true when the EbeanServer only uses Document store.
* Set to true when the Database only uses Document store.
*/
private boolean docStoreOnly;
@@ -229,6 +230,10 @@ public class ServerConfig {
private int persistBatchSize = 20;
private EnumType defaultEnumType = EnumType.ORDINAL;
private boolean disableLazyLoading;
/**
* The default batch size for lazy loading
*/
@@ -250,6 +255,8 @@ public class ServerConfig {
private boolean ddlRun;
private boolean ddlExtra = true;
private boolean ddlCreateOnly;
private String ddlInitSql;
@@ -346,7 +353,7 @@ public class ServerConfig {
/**
* Behaviour of updates in JDBC batch to by default include all properties.
*/
private boolean updateAllPropertiesInBatch = true;
private boolean updateAllPropertiesInBatch;
/**
* Default behaviour for updates when cascade save on a O2M or M2M to delete any missing children.
@@ -364,9 +371,10 @@ public class ServerConfig {
private UuidVersion uuidVersion = UuidVersion.VERSION4;
/**
* The UUID state file (for Version 1 UUIDs).
* The UUID state file (for Version 1 UUIDs). By default, the file is created in
* ${HOME}/.ebean/${servername}-uuid.state
*/
private String uuidStateFile = "ebean-uuid.state";
private String uuidStateFile;
/**
* The clock used for setting the timestamps (e.g. @UpdatedTimestamp) on objects.
@@ -484,6 +492,11 @@ public class ServerConfig {
*/
private boolean notifyL2CacheInForeground;
/**
* Set to true to support query plan capture.
*/
private boolean collectQueryPlans;
/**
* The time in millis used to determine when a query is alerted for being slow.
*/
@@ -511,8 +524,12 @@ public class ServerConfig {
*/
private boolean idGeneratorAutomatic = true;
private boolean dumpMetricsOnShutdown;
private String dumpMetricsOptions;
/**
* Construct a Server Configuration for programmatically creating an EbeanServer.
* Construct a Database Configuration for programmatically creating an Database.
*/
public ServerConfig() {
@@ -592,6 +609,47 @@ public class ServerConfig {
return serviceObject.get(key);
}
/**
* Put a service object into configuration such that it can be passed to a plugin.
*
* <pre>{@code
*
* JedisPool jedisPool = ..
*
* serverConfig.putServiceObject(jedisPool);
*
* }</pre>
*/
public void putServiceObject(Object configObject) {
String key = serviceObjectKey(configObject);
serviceObject.put(key, configObject);
}
private String serviceObjectKey(Object configObject) {
return serviceObjectKey(configObject.getClass());
}
private String serviceObjectKey(Class<?> cls) {
String simpleName = cls.getSimpleName();
return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
}
/**
* Used by plugins to obtain service objects.
*
* <pre>{@code
*
* JedisPool jedisPool = serverConfig.getServiceObject(JedisPool.class);
*
* }</pre>
*
* @param cls The type of the service object to obtain
* @return The service object given the class type
*/
public <P> P getServiceObject(Class<P> cls) {
return (P) serviceObject.get(serviceObjectKey(cls));
}
/**
* Return the Jackson JsonFactory to use.
* <p>
@@ -642,14 +700,14 @@ public class ServerConfig {
}
/**
* Return the name of the EbeanServer.
* Return the name of the Database.
*/
public String getName() {
return name;
}
/**
* Set the name of the EbeanServer.
* Set the name of the Database.
*/
public void setName(String name) {
this.name = name;
@@ -658,8 +716,8 @@ public class ServerConfig {
/**
* Return the container / clustering configuration.
* <p/>
* The container holds all the EbeanServer instances and provides clustering communication
* services to all the EbeanServer instances.
* The container holds all the Database instances and provides clustering communication
* services to all the Database instances.
*/
public ContainerConfig getContainerConfig() {
return containerConfig;
@@ -668,8 +726,8 @@ public class ServerConfig {
/**
* Set the container / clustering configuration.
* <p/>
* The container holds all the EbeanServer instances and provides clustering communication
* services to all the EbeanServer instances.
* The container holds all the Database instances and provides clustering communication
* services to all the Database instances.
*/
public void setContainerConfig(ContainerConfig containerConfig) {
this.containerConfig = containerConfig;
@@ -709,8 +767,8 @@ public class ServerConfig {
}
/**
* Set false if you do not want this EbeanServer to be registered as the "default" server
* with the Ebean singleton.
* Set false if you do not want this Database to be registered as the "default" database
* with the DB singleton.
* <p>
* This is only used when {@link #setRegister(boolean)} is also true.
* </p>
@@ -927,6 +985,30 @@ public class ServerConfig {
this.queryBatchSize = queryBatchSize;
}
public EnumType getDefaultEnumType() {
return defaultEnumType;
}
public void setDefaultEnumType(EnumType defaultEnumType) {
this.defaultEnumType = defaultEnumType;
}
/**
* Return true if lazy loading is disabled on queries by default.
*/
public boolean isDisableLazyLoading() {
return disableLazyLoading;
}
/**
* Set to true to disable lazy loading by default.
* <p>
* It can be turned on per query via {@link Query#setDisableLazyLoading(boolean)}.
*/
public void setDisableLazyLoading(boolean disableLazyLoading) {
this.disableLazyLoading = disableLazyLoading;
}
/**
* Return the default batch size for lazy loading of beans and collections.
*/
@@ -1480,14 +1562,14 @@ public class ServerConfig {
}
/**
* Return true if this EbeanServer is a Document store only instance (has no JDBC DB).
* Return true if this Database is a Document store only instance (has no JDBC DB).
*/
public boolean isDocStoreOnly() {
return docStoreOnly;
}
/**
* Set to true if this EbeanServer is Document store only instance (has no JDBC DB).
* Set to true if this Database is Document store only instance (has no JDBC DB).
*/
public void setDocStoreOnly(boolean docStoreOnly) {
this.docStoreOnly = docStoreOnly;
@@ -1887,16 +1969,16 @@ public class ServerConfig {
}
/**
* Return true if the EbeanServer instance should be created in offline mode.
* Return true if the Database instance should be created in offline mode.
*/
public boolean isDbOffline() {
return dbOffline;
}
/**
* Set to true if the EbeanServer instance should be created in offline mode.
* Set to true if the Database instance should be created in offline mode.
* <p>
* Typically used to create an EbeanServer instance for DDL Migration generation
* Typically used to create an Database instance for DDL Migration generation
* without requiring a real DataSource / Database to connect to.
* </p>
*/
@@ -1965,6 +2047,15 @@ public class ServerConfig {
* Return the UUID state file.
*/
public String getUuidStateFile() {
if (uuidStateFile == null || uuidStateFile.isEmpty()) {
// by default, add servername...
uuidStateFile = name + "-uuid.state";
// and store it in the user's home directory
String homeDir = System.getProperty("user.home");
if (homeDir != null && homeDir.isEmpty()) {
uuidStateFile = homeDir + "/.ebean/" + uuidStateFile;
}
}
return uuidStateFile;
}
@@ -2042,6 +2133,16 @@ public class ServerConfig {
this.ddlRun = ddlRun;
}
/**
* Set to false if you not want to run the extra-ddl.xml scripts. (default = true)
* <p>
* Typically we want this on when we are running tests.
*/
public void setDdlExtra(boolean ddlExtra) {
this.ddlExtra = ddlExtra;
}
/**
* Return true if the "drop all ddl" should be skipped.
* <p>
@@ -2112,6 +2213,13 @@ public class ServerConfig {
return ddlRun;
}
/**
* Return true, if extra-ddl.xml should be executed.
*/
public boolean isDdlExtra() {
return ddlExtra;
}
/**
* Return true if the class path search should be disabled.
*/
@@ -2121,7 +2229,7 @@ public class ServerConfig {
/**
* Set to true to disable the class path search even for the case where no entity bean classes
* have been registered. This can be used to start an EbeanServer instance just to use the
* have been registered. This can be used to start an Database instance just to use the
* SQL functions such as SqlQuery, SqlUpdate etc.
*/
public void setDisableClasspathSearch(boolean disableClasspathSearch) {
@@ -2235,8 +2343,7 @@ public class ServerConfig {
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
* try (Transaction transaction = DB.beginTransaction()) {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
@@ -2244,7 +2351,7 @@ public class ServerConfig {
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
* DB.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
@@ -2263,9 +2370,6 @@ public class ServerConfig {
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
@@ -2333,7 +2437,7 @@ public class ServerConfig {
}
/**
* Return true if the ebeanServer should collection query statistics by ObjectGraphNode.
* Return true if query statistics should be collected by ObjectGraphNode.
*/
public boolean isCollectQueryStatsByNode() {
return collectQueryStatsByNode;
@@ -2736,20 +2840,6 @@ public class ServerConfig {
return list;
}
/**
* Deprecated - this does nothing now, we always try to read test configuration.
* <p>
* Load settings from test-ebean.properties and do nothing if the properties is not found.
* <p>
* This is typically used when test-ebean.properties is put into the test class path and used
* to configure Ebean for running tests.
* </p>
*/
@Deprecated
public void loadTestProperties() {
// do nothing now ... as we always try to read test configuration and that should only
}
/**
* Return the properties that we used for configuration and were set via a call to loadFromProperties().
*/
@@ -2817,8 +2907,11 @@ public class ServerConfig {
}
loadDocStoreSettings(p);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds);
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans);
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
@@ -2887,6 +2980,8 @@ public class ServerConfig {
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
jodaLocalTimeMode = p.get("jodaLocalTimeMode", jodaLocalTimeMode);
defaultEnumType = p.getEnum(EnumType.class, "defaultEnumType", defaultEnumType);
disableLazyLoading = p.getBoolean("disableLazyLoading", disableLazyLoading);
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
@@ -2900,6 +2995,7 @@ public class ServerConfig {
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun);
ddlExtra = p.getBoolean("ddl.extra", ddlExtra);
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
ddlInitSql = p.get("ddl.initSql", ddlInitSql);
ddlSeedSql = p.get("ddl.seedSql", ddlSeedSql);
@@ -3183,6 +3279,50 @@ public class ServerConfig {
this.idGeneratorAutomatic = idGeneratorAutomatic;
}
/**
* Return true if query plan capture is enabled.
*/
public boolean isCollectQueryPlans() {
return collectQueryPlans;
}
/**
* Set to true to enable query plan capture.
*/
public void setCollectQueryPlans(boolean collectQueryPlans) {
this.collectQueryPlans = collectQueryPlans;
}
/**
* Return true if metrics should be dumped when the server is shutdown.
*/
public boolean isDumpMetricsOnShutdown() {
return dumpMetricsOnShutdown;
}
/**
* Set to true if metrics should be dumped when the server is shutdown.
*/
public void setDumpMetricsOnShutdown(boolean dumpMetricsOnShutdown) {
this.dumpMetricsOnShutdown = dumpMetricsOnShutdown;
}
/**
* Return the options for dumping metrics.
*/
public String getDumpMetricsOptions() {
return dumpMetricsOptions;
}
/**
* Include 'sql' or 'hash' in options such that they are included in the output.
*
* @param dumpMetricsOptions Example "sql,hash", "sql"
*/
public void setDumpMetricsOptions(String dumpMetricsOptions) {
this.dumpMetricsOptions = dumpMetricsOptions;
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -49,6 +49,8 @@ public class DatabasePlatform {
*/
protected boolean useExtraTransactionOnIterateSecondaryQueries;
protected boolean supportsDeleteTableAlias;
/**
* The behaviour used when ending a read only transaction at read committed isolation level.
*/
@@ -64,8 +66,6 @@ public class DatabasePlatform {
*/
protected String closeQuote = "\"";
protected String concatOperator = "||";
/**
* When set to true all db column names and table names use quoted identifiers.
*/
@@ -180,7 +180,15 @@ public class DatabasePlatform {
protected boolean forwardOnlyHintOnFindIterate;
/**
* By default we use JDBC batch when cascading (except for SQL Server).
* If set then use the CONCUR_UPDATABLE hint when creating ResultSets.
*
* This is {@code false} for HANA
*/
protected boolean supportsResultSetConcurrencyModeUpdatable = true;
/**
* By default we use JDBC batch when cascading (except for SQL Server and HANA).
*/
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
@@ -300,6 +308,13 @@ public class DatabasePlatform {
return supportsNativeIlike;
}
/**
* Return true if the platform supports delete statements with table alias.
*/
public boolean isSupportsDeleteTableAlias() {
return supportsDeleteTableAlias;
}
/**
* Return the maximum table name length.
* <p>
@@ -455,13 +470,6 @@ public class DatabasePlatform {
return openQuote;
}
/**
* Return the DB concat operator.
*/
public String getConcatOperator() {
return concatOperator;
}
/**
* Return the JDBC type used to store booleans.
*/
@@ -526,6 +534,24 @@ public class DatabasePlatform {
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
}
/**
* Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on
* createNativeSqlTree() PreparedStatements.
* <p>
* This specifically is required for Hana which doesn't support CONCUR_UPDATABLE
* </p>
*/
public boolean isSupportsResultSetConcurrencyModeUpdatable() {
return supportsResultSetConcurrencyModeUpdatable;
}
/**
* Set to true if the ResultSet CONCUR_UPDATABLE Hint should be used by default on createNativeSqlTree() PreparedStatements.
*/
public void setSupportsResultSetConcurrencyModeUpdatable(boolean supportsResultSetConcurrencyModeUpdatable) {
this.supportsResultSetConcurrencyModeUpdatable = supportsResultSetConcurrencyModeUpdatable;
}
/**
* Normally not needed - overridden in CockroachPlatform.
*/
@@ -8,7 +8,9 @@ import java.util.regex.Pattern;
*/
public class DbIdentity {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
private static final String TABLE_PLACEHOLDER = "{table}";
private static final Pattern TABLE_REPLACE = Pattern.compile(TABLE_PLACEHOLDER, Pattern.LITERAL);
/**
* Set if this DB supports sequences. Note some DB's support both Sequences
@@ -53,7 +55,9 @@ public class DbIdentity {
if (selectLastInsertedIdTemplate == null) {
return null;
}
if (!selectLastInsertedIdTemplate.contains(TABLE_PLACEHOLDER)) {
return selectLastInsertedIdTemplate;
}
return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table));
}
@@ -27,6 +27,9 @@ public class DbPlatformTypeMapping {
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
@SuppressWarnings("unused")
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
@@ -106,6 +109,7 @@ public class DbPlatformTypeMapping {
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_NATIVE);
} else {
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
@@ -121,6 +125,7 @@ public class DbPlatformTypeMapping {
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
// default to native UUID and override on platform configure()
put(DbType.UUID, UUID_NATIVE);
put(DbType.INET, INET_VARCHAR);
}
}
@@ -35,6 +35,8 @@ public enum DbType {
ARRAY(Types.ARRAY),
UUID(ExtraDbTypes.UUID),
INET(ExtraDbTypes.INET),
CDIR(ExtraDbTypes.CDIR),
POINT(ExtraDbTypes.POINT),
POLYGON(ExtraDbTypes.POLYGON),
@@ -40,6 +40,9 @@ public interface ExtraDbTypes {
*/
int JSONBlob = 5005;
int INET = 5020;
int CDIR = 5021;
/**
* Geo Point
*/
@@ -0,0 +1,58 @@
package io.ebean.config.dbplatform.clickhouse;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import java.sql.Types;
public class ClickHousePlatform extends DatabasePlatform {
public ClickHousePlatform() {
super();
this.platform = Platform.CLICKHOUSE;
//this.dbEncrypt =
//this.historySupport =
//this.exceptionTranslator =
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
this.columnAliasPrefix = null;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSupportsSequence(false);
this.dbIdentity.setSupportsIdentity(true);
this.booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("UInt8"));
// using unsigned as default types ...
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("UInt8", false));
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("UInt16", false));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("UInt32", false));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16,4));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("Float64", false));
dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("DateTime", false));
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("String", false));
dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CDIR, new DbPlatformType("String", false));
}
@Override
public boolean isNativeArrayType() {
return true;
}
}
@@ -23,6 +23,7 @@ public class H2Platform extends DatabasePlatform {
this.dbEncrypt = new H2DbEncrypt();
this.historySupport = new H2HistorySupport();
this.nativeUuidType = true;
this.supportsDeleteTableAlias = true;
this.dbDefaultValue.setNow("now()");
this.columnAliasPrefix = null;
@@ -0,0 +1,24 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.config.dbplatform.BasicSqlLimiter;
public class HanaBasicSqlLimiter implements BasicSqlLimiter {
@Override
public String limit(String dbSql, int firstRow, int maxRows) {
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append(dbSql);
if (maxRows > 0) {
sb.append(" ").append("limit");
sb.append(" ").append(maxRows);
if (firstRow > 0) {
sb.append(" ").append("offset").append(" ");
sb.append(firstRow);
}
}
return sb.toString();
}
}
@@ -0,0 +1,27 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.config.dbplatform.DbStandardHistorySupport;
public class HanaHistorySupport extends DbStandardHistorySupport {
@Override
public String getAsOfViewSuffix(String asOfViewSuffix) {
return " for system_time as of ?";
}
@Override
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
return " for system_time between ? and ?";
}
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_start";
}
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_end";
}
}
@@ -0,0 +1,96 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.Query.ForUpdate;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.config.PlatformConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.SqlErrorCodes;
public class HanaPlatform extends DatabasePlatform {
public HanaPlatform() {
this.platform = Platform.HANA;
this.sqlLimiter = new HanaSqlLimiter();
this.persistBatchOnCascade = PersistBatch.NONE;
this.supportsResultSetConcurrencyModeUpdatable = false;
this.columnAliasPrefix = null;
this.historySupport = new HanaHistorySupport();
this.basicSqlLimiter = new HanaBasicSqlLimiter();
this.likeClauseRaw = "like ?";
this.maxConstraintNameLength = 127;
this.maxTableNameLength = 127;
this.dbDefaultValue.setNow("current_timestamp");
this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("131", "133", "146")
.addDataIntegrity("130", "429", "461", "462").addDuplicateKey("144", "301", "349").build();
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSelectLastInsertedIdTemplate("select current_identity_value() from sys.dummy");
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSupportsIdentity(true);
this.dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false));
this.dbTypeMap.put(DbType.BINARY, new DbPlatformType("varbinary", 255));
this.dbTypeMap.put(DbType.BIT, new DbPlatformType("smallint", false));
this.dbTypeMap.put(DbType.BLOB, new DbPlatformType("blob", false));
this.dbTypeMap.put(DbType.CHAR, new DbPlatformType("nvarchar", 255));
this.dbTypeMap.put(DbType.CLOB, new DbPlatformType("nclob", false));
this.dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
this.dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("nvarchar", 255));
this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry"));
this.dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob", false));
this.dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nclob", false));
this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry"));
this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry"));
this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry"));
this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point"));
this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry"));
this.dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("smallint", false));
this.dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint", false));
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40));
this.dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
this.dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255));
}
@Override
protected void addGeoTypes(int srid) {
this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false));
this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false));
this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry(" + srid + ")", false));
this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry(" + srid + ")", false));
this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point(" + srid + ")", false));
this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry(" + srid + ")", false));
}
@Override
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
switch (forUpdateMode) {
case BASE:
return sql + " for update";
case NOWAIT:
return sql + " for update nowait";
case SKIPLOCKED:
return sql + " for update ignore locked";
default:
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
}
}
@Override
protected void configure(PlatformConfig config, boolean allQuotedIdentifiers) {
super.configure(config, allQuotedIdentifiers);
if (config.getDbUuid().useBinary()) {
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varbinary", 16));
} else {
this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40));
}
}
}
@@ -0,0 +1,35 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.config.dbplatform.SqlLimitRequest;
import io.ebean.config.dbplatform.SqlLimitResponse;
import io.ebean.config.dbplatform.SqlLimiter;
public class HanaSqlLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
int firstRow = request.getFirstRow();
int maxRows = request.getMaxRows();
if (maxRows > 0) {
sb.append(" ").append("limit ").append(maxRows);
if (firstRow > 0) {
sb.append(" ").append("offset ");
sb.append(firstRow);
}
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql, false);
}
}
@@ -0,0 +1,4 @@
/**
* SAP HANA specific support.
*/
package io.ebean.config.dbplatform.hana;
@@ -23,6 +23,7 @@ public class OraclePlatform extends DatabasePlatform {
public OraclePlatform() {
super();
this.platform = Platform.ORACLE;
this.supportsDeleteTableAlias = true;
this.maxTableNameLength = 30;
this.maxConstraintNameLength = 30;
this.dbEncrypt = new OracleDbEncrypt();
@@ -30,6 +30,7 @@ public class PostgresPlatform extends DatabasePlatform {
super();
this.platform = Platform.POSTGRES;
this.supportsNativeIlike = true;
this.supportsDeleteTableAlias = true;
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
@@ -60,6 +61,7 @@ public class PostgresPlatform extends DatabasePlatform {
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
@@ -136,8 +138,9 @@ public class PostgresPlatform extends DatabasePlatform {
/**
* Return SQL using built in partition helper functions to create some initial partitions.
*
* Only use this if extra-dll doesn't have some initial partitions defined (which it should).
* Only use this if extra-ddl doesn't have some initial partitions defined (which it should).
*/
@Override
public String tablePartitionInit(String tableName, PartitionMode mode, String property, String pkey) {
if (property == null) {
property = "";
+2 -2
View File
@@ -1,10 +1,10 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Configuration settings for EbeanServer construction</TITLE>
<TITLE>Configuration settings for Database construction</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Configuration settings for EbeanServer construction
Configuration settings for Database construction
</Body>
</HTML>
@@ -63,6 +63,7 @@ class Loader {
*/
private void loadTest() {
loadProperties("application-test.properties", Source.RESOURCE);
loadYaml("application-test.yaml", Source.RESOURCE);
loadYaml("application-test.yml", Source.RESOURCE);
loadProperties("test-ebean.properties", Source.RESOURCE);
}
@@ -83,6 +84,7 @@ class Loader {
* Load the main configuration for the given source.
*/
private void loadMain(Source source) {
loadYaml("application.yaml", source);
loadYaml("application.yml", source);
loadProperties("application.properties", source);
loadProperties("ebean.properties", source);
@@ -95,11 +97,13 @@ class Loader {
if (fileName != null) {
loadWithExtensionCheck(fileName);
}
} else {
loadWithExtensionCheck(fileName);
}
}
void loadWithExtensionCheck(String fileName) {
if (fileName.endsWith("yml")) {
if (fileName.endsWith("yaml") || fileName.endsWith("yml")) {
loadYaml(fileName, Source.FILE);
} else if (fileName.endsWith("properties")) {
loadProperties(fileName, Source.FILE);
@@ -18,14 +18,14 @@ public class PropertiesLoader {
* <p>Firstly loads from main resources</p>
* <pre>
* - application.properties
* - application.yml
* - application.yaml
* - ebean.properties
* </pre>
* <p>
* <p>Then loads from local files</p>
* <pre>
* - application.properties
* - application.yml
* - application.yaml
* - ebean.properties
* </pre>
* <p>
@@ -41,7 +41,7 @@ public class PropertiesLoader {
* <p>Loads from test resources</p>
* <pre>
* - application-test.properties
* - application-test.yml
* - application-test.yaml
* - test-ebean.properties
* </pre>
*/
@@ -7,6 +7,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
/**
@@ -49,6 +50,11 @@ public interface DbMigration {
throw new IllegalStateException("No service implementation found for DbMigration?");
}
/**
* Set to false to suppress logging to System out.
*/
void setLogToSystemOut(boolean logToSystemOut);
/**
* Set the path from the current working directory to the application resources.
* <p>
@@ -148,7 +154,12 @@ public interface DbMigration {
void addDatabasePlatform(DatabasePlatform databasePlatform, String prefix);
/**
* Generate the next migration xml file and associated apply and rollback sql scripts.
* Return the list of versions that contain pending drops.
*/
List<String> getPendingDrops();
/**
* Generate the next migration sql script and associated model xml.
* <p>
* This does not run the migration or ddl scripts but just generates them.
* </p>
@@ -180,4 +191,15 @@ public interface DbMigration {
* @return the version of the generated migration or null
*/
String generateMigration() throws IOException;
/**
* Generate an "init" migration which has all changes.
* <p>
* An "init" migration can only be executed and used on a database that has had no
* prior migrations run on it.
* </p>
* @return the version of the generated migration
*/
String generateInitMigration() throws IOException;
}
@@ -9,7 +9,7 @@ package io.ebean.event;
* <p>
* Note that getTransaction() on the PersistRequest returns the transaction used
* for the insert, update, delete or fetch. To explicitly use this same
* transaction you should use this transaction via methods on EbeanServer.
* transaction you should use this transaction via methods on Database.
* </p>
* <pre>{@code
*
@@ -1,6 +1,6 @@
package io.ebean.event;
import io.ebean.EbeanServer;
import io.ebean.Database;
/**
* Fired after a bean is constructed, but not yet loaded from database.
@@ -9,7 +9,7 @@ import io.ebean.EbeanServer;
* properties will get unload. Use {@link BeanPostLoad} instead.
* <p>
* it's intended to do some dependency-injection here.
* If you plan to use this feature you should use {@link EbeanServer#createEntityBean(Class)}
* If you plan to use this feature you should use {@link Database#createEntityBean(Class)}
* to create new beans.
* </p>
*/
@@ -32,7 +32,7 @@ public interface BeanPostConstructListener {
void postConstruct(Object bean);
/**
* Called after {@link EbeanServer#createEntityBean(Class)}. Only for new beans.
* Called after {@link Database#createEntityBean(Class)}. Only for new beans.
* intended to set default values here.
*/
void postCreate(Object bean);
@@ -6,7 +6,7 @@ import java.util.List;
/**
* A simple MetricVisitor that can collect the desired metrics into lists.
*/
public class BasicMetricVisitor extends AbstractMetricVisitor {
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
private final List<MetaTimedMetric> timed = new ArrayList<>();
private final List<MetaQueryMetric> dtoQuery = new ArrayList<>();
@@ -29,6 +29,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
/**
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
*/
@Override
public List<MetaTimedMetric> getTimedMetrics() {
return timed;
}
@@ -36,6 +37,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
/**
* Return the DTO query metrics.
*/
@Override
public List<MetaQueryMetric> getDtoQueryMetrics() {
return dtoQuery;
}
@@ -43,6 +45,7 @@ public class BasicMetricVisitor extends AbstractMetricVisitor {
/**
* Return the ORM query metrics.
*/
@Override
public List<MetaOrmQueryMetric> getOrmQueryMetrics() {
return ormQuery;
}
@@ -3,10 +3,24 @@ package io.ebean.meta;
import java.util.List;
/**
* Provides access to the meta data in EbeanServer such as query execution statistics.
* Provides access to the meta data in Database such as query execution statistics.
*/
public interface MetaInfoManager {
/**
* Return the metrics for the database instance.
* <p>
* This will reset the metrics (reset counters back to zero etc) and
* will only return the non-empty metrics.
* </p>
*/
ServerMetrics collectMetrics();
/**
* Collect query plans.
*/
List<MetaQueryPlan> collectQueryPlans(QueryPlanRequest request);
/**
* Visit the metrics resetting and collecting/reporting as desired.
*/
@@ -1,7 +1,5 @@
package io.ebean.meta;
import io.ebean.ProfileLocation;
import java.util.List;
/**
@@ -9,11 +7,6 @@ import java.util.List;
*/
public interface MetaOrmQueryMetric extends MetaQueryMetric {
/**
* Return the profile location.
*/
ProfileLocation getProfileLocation();
/**
* Return true if this query plan was tuned by AutoTune.
*/
@@ -1,5 +1,7 @@
package io.ebean.meta;
import io.ebean.ProfileLocation;
/**
* Query execution metrics.
*/
@@ -15,6 +17,11 @@ public interface MetaQueryMetric extends MetaTimedMetric {
*/
String getLabel();
/**
* Return the profile location.
*/
ProfileLocation getProfileLocation();
/**
* The actual SQL of the query.
*/
@@ -0,0 +1,23 @@
package io.ebean.meta;
public interface MetaQueryPlan {
Class<?> getBeanType();
/**
* Return a string representation of the query plan hash.
*/
String getQueryPlanHash();
String getLabel();
String getSql();
String getBind();
String getPlan();
long getQueryTimeMicros();
long getCaptureCount();
}
+6 -1
View File
@@ -25,6 +25,11 @@ public enum MetricType {
* <p>
* SqlQuery and SqlUpdate without a label have no metrics collected.
*/
SQL
SQL,
/**
* L2 cache metrics.
*/
L2
}
@@ -0,0 +1,97 @@
package io.ebean.meta;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Request used to capture query plans.
*/
public class QueryPlanRequest {
private List<MetaQueryPlan> plans = new ArrayList<>();
private Connection connection;
private boolean store;
private long since;
private Set<Class<?>> includedBeanTypes;
private Set<String> includedLabels;
public List<MetaQueryPlan> getPlans() {
return plans;
}
/**
* Return the connection to use to capture the query plans.
*/
public Connection getConnection() {
return connection;
}
/**
* Set the connection to use to capture the query plans.
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/**
* Return true if the captured query plan is stored.
*/
public boolean isStore() {
return store;
}
/**
* Set to true to store the captured query plan.
*/
public void setStore(boolean store) {
this.store = store;
}
/**
* Return the epoch time after which the query plan was capture (to be included).
*/
public long getSince() {
return since;
}
/**
* Set the epoch time after which the query plan was captured.
* <p>
* This is used to only capture plans that have changed since a given time (like the time of last capture).
* </p>
*
* @param since The time after which the query plan was captured to be included
*/
public void setSince(long since) {
this.since = since;
}
/**
* Process consume the query plan.
*/
public void process(MetaQueryPlan plan) {
plans.add(plan);
}
/**
* Return true if the bean type should be included in the query plan capture.
*/
public boolean includeType(Class<?> beanType) {
return includedBeanTypes == null || includedBeanTypes.isEmpty() || includedBeanTypes.contains(beanType);
}
/**
* Return true if the label should be included in the query plan capture.
*/
public boolean includeLabel(String label) {
return includedLabels == null || includedLabels.isEmpty() || includedLabels.contains(label);
}
}
@@ -0,0 +1,24 @@
package io.ebean.meta;
import java.util.List;
/**
* Metrics of the Database instance.
*/
public interface ServerMetrics {
/**
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
*/
List<MetaTimedMetric> getTimedMetrics();
/**
* Return the DTO query metrics.
*/
List<MetaQueryMetric> getDtoQueryMetrics();
/**
* Return the ORM query metrics.
*/
List<MetaOrmQueryMetric> getOrmQueryMetrics();
}
@@ -0,0 +1,80 @@
package io.ebean.meta;
import java.util.Comparator;
/**
* Comparator for timed metrics sorted by name and then count.
*/
public class SortMetric {
public static final Comparator<MetaTimedMetric> NAME = new Name();
public static final Comparator<MetaTimedMetric> COUNT = new Count();
public static final Comparator<MetaTimedMetric> TOTAL = new Total();
public static final Comparator<MetaTimedMetric> MEAN = new Mean();
public static final Comparator<MetaTimedMetric> MAX = new Max();
/**
* Sort by name.
*/
public static class Name implements Comparator<MetaTimedMetric> {
@Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
String name = o1.getName();
String name2 = o2.getName();
if (name == null) {
return name2 == null ? 0 : -1;
}
if (name2 == null) {
return 1;
}
int i = name.compareTo(name2);
return i != 0 ? i : Long.compare(o1.getCount(), o2.getCount());
}
}
/**
* Sort by count desc.
*/
public static class Count implements Comparator<MetaTimedMetric> {
@Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getCount(), o1.getCount());
}
}
/**
* Sort by total time desc.
*/
public static class Total implements Comparator<MetaTimedMetric> {
@Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getTotal(), o1.getTotal());
}
}
/**
* Sort by mean desc.
*/
public static class Mean implements Comparator<MetaTimedMetric> {
@Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getMean(), o1.getMean());
}
}
/**
* Sort by max desc.
*/
public static class Max implements Comparator<MetaTimedMetric> {
@Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getMax(), o1.getMax());
}
}
}
@@ -1,4 +1,4 @@
/**
* Meta data that can be retrieved for the EbeanServer.
* Meta data that can be retrieved for a Database instance.
*/
package io.ebean.meta;
@@ -1,5 +1,6 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.ProfileLocation;
import io.ebean.meta.MetricType;
/**
@@ -27,6 +28,6 @@ public interface MetricFactory {
/**
* Create a Timed metric.
*/
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, String sql);
QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class<?> type, String label, ProfileLocation profileLocation, String sql);
}
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebeaninternal.server.profile.DMetricFactory;
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.meta.MetaQueryMetric;
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.meta.MetricVisitor;
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.meta.MetricVisitor;
@@ -17,6 +17,16 @@ public interface TimedMetric {
*/
void add(long micros, long beans);
/**
* Add a time event given the start nanos.
*/
void addSinceNanos(long startNanos);
/**
* Add a time event given the start nanos and bean count.
*/
void addSinceNanos(long startNanos, long beans);
/**
* Return true if there are no metrics collected since the last collection.
*/
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.meta.MetricVisitor;
@@ -7,6 +7,16 @@ import io.ebean.meta.MetricVisitor;
*/
public interface TimedMetricMap {
/**
* Add a time event given the start nanos.
*/
void addSinceNanos(String key, long startNanos);
/**
* Add a time event given the start nanos and beans.
*/
void addSinceNanos(String key, long startNanos, int beans);
/**
* Add an execution for the given key.
*/
@@ -1,4 +1,4 @@
package io.ebeaninternal.metric;
package io.ebean.metric;
import io.ebean.meta.MetaTimedMetric;
+10 -116
View File
@@ -3,130 +3,24 @@
<title>Ebean API</title>
</head>
<body BGCOLOR="#ffffff">
Ebean Object Relational Mapping (start at
<a href='com/avaje/ebean/EbeanServer.html'>EbeanServer</a> or <a href='com/avaje/ebean/Ebean.html'>Ebean</a>).
Ebean Object Relational Mapping -
<a href='io/ebean/Database.html'>Database</a> or <a href='io/ebean/DB.html'>DB</a>).
<h3>Ebean</h3>
<h4><a href='io/ebean/Database.html'>Database</a></h4>
<p>
Provides the main API for fetching and persisting beans with Ebean.
Database provides the main API for fetching and persisting beans.
</p>
<h4><a href='io/ebean/DB.html'>DB</a></h4>
<p>
For a full description of the query language refer to <a href="com/avaje/ebean/Query.html">Query</a>.
DB holds a registry of Database instances by name.
</p>
<h4><a href='https://ebean.io/docs/query'>Query</a></h4>
<p>
&nbsp;
Review the documentation for the query capabilities.
</p>
<div id="overviewexamples">
<h3>
EXAMPLE 1: Simple fetch
</h3>
<pre>{@code
// fetch order 10
Order order = Ebean.find(Order.class, 10);
}</pre>
<h3>
EXAMPLE 2: Fetch an Object with associations
</h3>
<pre>{@code
// fetch Customer 7 including their billing and shipping addresses
Customer customer = Ebean.find(Customer.class)
.fetch("billingAddress");
.fetch("shippingAddress");
.setId(7)
.findOne();
Address billAddr = customer.getBillingAddress();
Address shipAddr = customer.getShippingAddress();
}</pre>
<h3>
EXAMPLE 3: Fetch a list of Objects with associations
</h3>
<pre>{@code
// Note: This example shows a "Partial Object".
// For the product objects associated with the
// order details only the product id and name is
// fetched (the product objects are partially populated).
// fetch orders for customer.id = 2
List<Order> orderList = Ebean.find(Order.class);
.fetch("customer")
.fetch("customer.shippingAddress")
.fetch("details")
.fetch("details.product","name")
.where().eq("customer.id",2)
.findList();
// Note: Only the product id and name is fetched for the
// product details. This is referred to as a
// "Partial Object" (one that is partially populated).
// code that traverses the object graph...
Order order = orderList.get(0);
Customer customer = order.getCustomer();
Address shipAddr = customer.getShippingAddress();
List<OrderDetail> details = order.getDetails();
OrderDetail detail = details.get(0);
Product product = detail.getProduct();
String productName = product.getName();
}</pre>
<h3>
EXAMPLE 4: Create and save an Order
</h3>
<pre>{@code
// get a Customer reference so we don't hit the database
Customer custRef = Ebean.getReference(Customer.class, 7);
// create a new Order object
Order newOrder = new Order();
newOrder.setStatus(Order.Status.NEW);
newOrder.setCustomer(custRef);
ArrayList orderLines = new ArrayList();
newOrder.setLines(orderLines);
...
// add a line to the order
Product prodRef = Ebean.getReference(Product.class, 41);
OrderLine line = new OrderLine();
line.setProduct(prodRef);
line.setQuantity(10);
orderLines.add(line);
...
// save the order and its lines in a single transaction
// NB: assumes CascadeType.PERSIST is set on the order lines association
Ebean.save(newOrder);
}</pre>
<h3>
EXAMPLE 5: Use another database
</h3>
<pre>{@code
// Get access to the Human Resources EbeanServer/Database
EbeanServer hrServer = Ebean.getServer("HR");
// fetch contact 3 from the HR database
Contact contact = hrServer.find(Contact.class, 3);
contact.setStatus(Contact.Status.INACTIVE);
...
// save the contact back to the HR database
hrServer.save(contact);
}</pre>
</div>
</body>
+22 -60
View File
@@ -3,29 +3,38 @@
<TITLE>Ebean core API</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Core API (see <a href="EbeanServer.html">EbeanServer</a> and <a href="Ebean.html">Ebean</a>).
Core API (see <a href="Database.html">Database</a>, <a href="DB.html">DB</a> and <a href="Query.html">Query</a>).
<h3>Ebean</h3>
<h3>Database</h3>
<p>
Provides the main API for fetching and persisting beans with eBean.
Provides the main API for fetching and persisting beans. We can obtain the "default database"
via <code>DB.getDefault()</code> or just use methods on DB.
</p>
<pre>{@code
// EXAMPLE 1: Simple fetch
//========================
// fetch order 10
Order order = Ebean.find(Order.class, 10);
// Example find by id
Order order = DB.find(Order.class, 10);
// Example save
// EXAMPLE 2: Fetch an Object with associations
//=============================================
Customer customer = DB.getReference(Customer.class, 42);
// fetch Customer 7 including their billing and shipping addresses
Customer customer =
Ebean.find(Customer.class)
.setId(7)
Order newOrder = new Order();
newOrder.setStatus(Order.Status.NEW);
newOrder.setCustomer(customer);
...
DB.save(newOrder);
// Example: Eagerly fetching associations
// fetch Customer 42 including their billing and shipping addresses
Customer customer = DB.find(Customer.class)
.setId(42)
.fetch("billingAddress")
.fetch("shippingAddress")
.findOne();
@@ -33,53 +42,6 @@ Customer customer =
Address billAddr = customer.getBillingAddress();
Address shipAddr = customer.getShippingAddress();
// EXAMPLE 3: Create and save an Order
//=====================================
// get a Customer reference so we don't hit the database
Customer custRef = Ebean.getReference(Customer.class, 7);
// create a new Order object
Order newOrder = new Order();
newOrder.setStatus(Order.Status.NEW);
newOrder.setCustomer(custRef);
ArrayList orderLines = new ArrayList();
newOrder.setLines(orderLines);
...
// add a line to the order
Product prodRef = Ebean.getReference(Product.class, 41);
OrderLine line = new OrderLine();
line.setProduct(prodRef);
line.setQuantity(10);
orderLines.add(line);
...
// save the order and its lines in a single transaction
// NB: assumes CascadeType.PERSIST is set on the order lines association
Ebean.save(newOrder);
// EXAMPLE 4: Use another database
//=================================
// Get access to the Human Resources EbeanServer/Database
EbeanServer hrServer = Ebean.getServer(&quot;HR&quot;);
// fetch contact 3 from the HR database
Contact contact = hrServer.find(Contact.class, 3);
contact.setStatus(Contact.Status.INACTIVE);
...
// save the contact back to the HR database
hrServer.save(contact);
}</pre>
</Body>
@@ -9,6 +9,10 @@ import io.ebean.event.BeanQueryAdapter;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
/**
* Information and methods on BeanDescriptors made available to plugins.
@@ -18,6 +22,7 @@ public interface BeanType<T> {
/**
* Return the short name of the bean type.
*/
@Nonnull
String getName();
/**
@@ -28,11 +33,13 @@ public interface BeanType<T> {
/**
* Return the full name of the bean type.
*/
@Nonnull
String getFullName();
/**
* Return the class type this BeanDescriptor describes.
*/
@Nonnull
Class<T> getBeanType();
/**
@@ -43,6 +50,7 @@ public interface BeanType<T> {
/**
* Return all the properties for this bean type.
*/
@Nonnull
Collection<? extends Property> allProperties();
/**
@@ -197,6 +205,28 @@ public interface BeanType<T> {
*/
boolean hasInheritance();
/**
* Return true if this object is the root level object in its entity
* inheritance.
*/
boolean isInheritanceRoot();
/**
* Returns all direct children of this beantype
*/
List<BeanType<?>> getInheritanceChildren();
/**
* Returns the parent in inheritance hiearchy
*/
BeanType<?> getInheritanceParent();
/**
* Visit all children recursively
* @param visitor
*/
void visitAllInheritanceChildren(Consumer<BeanType<?>> visitor);
/**
* Return the discriminator column.
*/
@@ -73,4 +73,14 @@ public interface ExpressionPath {
* Return the Id values for the given bean value.
*/
Object[] getAssocIdValues(EntityBean bean);
/**
* Return the underlying bean property.
*/
public Property getProperty();
/**
* The ElPrefix plus name.
*/
String getElName();
}

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