Compare commits

..
Author SHA1 Message Date
rob bygrave 8e59e72983 [maven-release-plugin] prepare release ebean-parent-12.6.7 2021-02-12 22:27:34 +13:00
rob bygrave b56d68dac7 #2157 - ManyToMany mapping to itself results in broken generated SQL DDL when not defining @JoinTable. 2021-02-12 22:17:04 +13:00
Robin Bygrave 213562fcf1 No change - update ddl review for h2 2021-02-12 16:34:24 +13:00
Rob BygraveandGitHub d3a09b93c0 #2156 - Using @OneToOne(targetEntity...) with Interface field results in BeanNotRegisteredException (#2160) 2021-02-12 16:30:28 +13:00
Robin Bygrave 536ea57369 Merge branch 'master' of https://github.com/ebean-orm/ebean 2021-02-11 17:28:21 +13:00
Robin Bygrave ac1dd4cbab #2158 Refactor to use try with resources with Connection for platform selection via jdbc metaData 2021-02-11 17:28:05 +13:00
Robin Bygrave bc33e05906 #2158 - Oracle - automatic platform selection doesn't select older Oracle11Platform via jdbc metadata major version 2021-02-11 17:20:28 +13:00
rob bygrave 8ecc407cb0 #2154 - Fix tests for QueryBeans: TargetEntity is not evaluated during bean generation resulting in bad query beans 2021-02-10 19:25:42 +13:00
Robin Bygrave 2672dff512 #2155 - QueryBeans: Change to use own @Generated with retention RUNTIME 2021-02-10 15:28:55 +13:00
Robin Bygrave 74d907bbce Refactor kotlin querybean generator ProcessingContext extract asElement() method 2021-02-10 15:12:28 +13:00
Robin Bygrave 53aacabce7 #2154 - QueryBeans: TargetEntity is not evaluated during bean generation resulting in bad query beans 2021-02-10 15:10:03 +13:00
Robin Bygrave ab9cdd8f5b #2153 - QueryBeans: OneToMany Map property is handled as PScalar instead of TQAssocBean 2021-02-10 13:52:29 +13:00
Robin Bygrave b3d439ed11 Bump tile-maven-plugin to 2.19 2021-02-10 13:00:50 +13:00
Robin Bygrave d57657c209 #2127 - Fix for - Adding a new list of children to @OneToMany with orphanRemoval true does not delete existing orphans
Modifies EntityBeanIntercept preSetterMany to set the changed state on the many property and use this in SaveManyBeans to detect when the existing beans need orphan removal
2021-02-04 15:45:19 +13:00
Robin Bygrave dd080c5933 Test only change - refactor update TestBeanState 2021-02-04 15:19:34 +13:00
Rob BygraveandGitHub 0be98d7989 Fix to only cancel query once (#2152)
Change DefaultOrmQuery.cancel() to call underlying jdbc cancel once

- Refactor tidy already cancelled check (pre query execution)
- Remove unnecessary extra transaction.end() call on future query execution (as already handled by CallableQueryList etc)
2021-02-03 14:51:42 +13:00
rob bygrave fca54dbbe3 [maven-release-plugin] prepare for next development iteration 2021-01-24 17:42:50 +13:00
rob bygrave 7ec5fe6a85 [maven-release-plugin] prepare release ebean-parent-12.6.6 2021-01-24 17:42:38 +13:00
rob bygrave 9ea5505214 Bump to ebean agent 12.6.6 2021-01-24 17:40:13 +13:00
Robin Bygrave 75d3b566a7 Merge branch 'FOCONIS-prePersist-postPersist-fix-batch-flush-12' 2021-01-22 14:01:19 +13:00
Robin Bygrave e38059f52c #2149 - Fix for ADD: jdbc batch flush doesnt execute sql statements created in lifecycle methods (e.g. beans saved in PostInsert etc)
Note that the foconis fork has a onPersist extension which is removed from the test.
2021-01-22 14:00:48 +13:00
Robin Bygrave 72331aa945 Merge branch 'prePersist-postPersist-fix-batch-flush-12' of https://github.com/FOCONIS/ebean into FOCONIS-prePersist-postPersist-fix-batch-flush-12 2021-01-22 13:14:05 +13:00
Robin Bygrave e497c54f82 No effective change - modify test redis ClusterTest to have 20ms wait 2021-01-21 17:01:36 +13:00
Robin Bygrave b44091ff3a #2147 Fix for ADD: multiple to many outer joins cause wrong count in distinct count…
Copy of Rolands fix in FOCONIS branch. This also brings over some of the extra tests found there.

Note that the SQL is slightly different from the FOCONIS branch in that there is additional foreign key columns included in the sub-query select clause.
2021-01-21 16:56:42 +13:00
Robin Bygrave 2ab889f889 Merge branch 'FOCONIS-count-distinct-with-two-joins-12' 2021-01-21 14:50:32 +13:00
Robin Bygrave 23541e661e Merge branch 'count-distinct-with-two-joins-12' of https://github.com/FOCONIS/ebean into FOCONIS-count-distinct-with-two-joins-12 2021-01-21 14:45:56 +13:00
trojo 6778e37652 ADD: batch flash doesnt execute sql statements created in lifecycle methods 2021-01-20 17:43:14 +01:00
rob bygrave 5eac31283d #2148 - PersistenceException: No ScalarType registered for class java.util.LinkedHashMap 2021-01-20 23:31:45 +13:00
trojo 38016773d4 added comments 2021-01-20 10:47:53 +01:00
trojo ad80eb267f ADD: multiple to many outer joins cause wrong count in distinct count queries 2021-01-20 09:57:25 +01:00
rob bygrave 449e0832e0 Merge branch 'FOCONIS-cache-with-lazyload-wrong-12' 2021-01-20 21:37:57 +13:00
rob bygrave f28f5c9a01 #2146 - no change - Tidy test only TestWithCacheAndLazyLoad 2021-01-20 21:37:29 +13:00
rob bygrave 9dd28d8879 #2146 - Fix for Cache with lazy load doesnt work
When the list is empty() it has already been loaded and loading should skip the l2 cache
2021-01-20 21:10:49 +13:00
rob bygrave b47eec99a5 Merge branch 'cache-with-lazyload-wrong-12' of https://github.com/FOCONIS/ebean into FOCONIS-cache-with-lazyload-wrong-12 2021-01-20 20:36:18 +13:00
Robin Bygrave 99bb55efa0 No change - update ebean-test test configuration only for windows 2021-01-20 17:22:00 +13:00
Robin Bygrave 4408eb618a No change - update test only - TestHistoryOneToMany with wait for when run on windows 2021-01-20 17:11:07 +13:00
rob bygrave 9ccd1b1b27 No effective change - tidy whitespace in SqlTreeBuilder and SqlTreeNodeExtraJoin 2021-01-20 00:10:09 +13:00
rob bygrave 0c1657fef5 #2145 - SoftDelete predicate missing on join to ManyToOne supporting predicate expression 2021-01-20 00:00:27 +13:00
Noemi Szemenyei ee393c6485 ADD: testcase for wrong lazyload with cache 2021-01-19 11:41:19 +01:00
rob bygrave 7f68b9d846 No effective change - tidy whitespace in BeanDescriptorCacheHelp 2021-01-19 22:48:29 +13:00
rob bygrave 2035a3344e Merge branch 'FOCONIS-persistcontext-wrong' 2021-01-19 22:37:45 +13:00
rob bygrave ade36582a0 #2144 - Fix for NPE via Wrong beans in PersistContext avoid proper lazy load 2021-01-19 22:37:15 +13:00
Roland Praml a4b8be61e3 ADD: some suggestions/debug hints 2021-01-11 11:50:25 +01:00
Roland Praml b7feb62ecd ADD: testcase for broken lazyload 2021-01-11 11:50:05 +01:00
rob bygrave 7e48f7c8eb [maven-release-plugin] prepare for next development iteration 2021-01-05 18:02:21 +13:00
rob bygrave 501f8111fe [maven-release-plugin] prepare release ebean-parent-12.6.5 2021-01-05 18:02:09 +13:00
rob bygrave d8f4503d98 #2141 - Fix for failing test, revert of fix for #2127 2021-01-05 17:56:55 +13:00
Rob BygraveandGitHub 0d83978c58 Merge pull request #2141 from tobias-/failing_cascade_test_case_2
Failing testcase that shows wipe of all old children on save
2021-01-05 17:30:56 +13:00
Tobias 69e56be459 Failing testcase that shows wipe of all old children on save
When adding a child to a newly saved bean (A), all other children are
killed on save of A.
2020-12-28 15:35:15 +01:00
rob bygrave 35a721039d [maven-release-plugin] prepare for next development iteration 2020-12-23 20:25:47 +13:00
91 changed files with 1846 additions and 702 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean api</name>
@@ -931,10 +931,14 @@ public final class EntityBeanIntercept implements Serializable {
* OneToMany and ManyToMany only set loaded state.
*/
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
}
setChangedProperty(propertyIndex);
}
setLoadedProperty(propertyIndex);
}
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
@@ -59,7 +59,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
+17 -17
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean bom</name>
@@ -18,8 +18,8 @@
<ebean-migration.version>12.4.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.6.2</ebean-agent.version>
<ebean-maven-plugin.version>12.6.2</ebean-maven-plugin.version>
<ebean-agent.version>12.6.6</ebean-agent.version>
<ebean-maven-plugin.version>12.6.6</ebean-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -81,88 +81,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -21,7 +21,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
+6 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<properties>
@@ -92,19 +92,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
@@ -301,7 +301,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
@@ -131,19 +131,10 @@ public class DatabasePlatformFactory {
* Use JDBC DatabaseMetaData to determine the platform.
*/
private DatabasePlatform byDataSource(DataSource dataSource) {
Connection connection = null;
try {
connection = dataSource.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
return byDatabaseMeta(metaData, connection);
try (Connection connection = dataSource.getConnection()) {
return byDatabaseMeta(connection.getMetaData(), connection);
} catch (SQLException ex) {
throw new PersistenceException(ex);
} finally {
JdbcClose.close(connection);
}
}
@@ -157,7 +148,7 @@ public class DatabasePlatformFactory {
final int minorVersion = metaData.getDatabaseMinorVersion();
if (dbProductName.contains("oracle")) {
return new OraclePlatform();
return oracleVersion(majorVersion);
} else if (dbProductName.contains("microsoft")) {
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via DatabaseConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
} else if (dbProductName.contains("h2")) {
@@ -188,6 +179,10 @@ public class DatabasePlatformFactory {
return new DatabasePlatform();
}
private DatabasePlatform oracleVersion(int majorVersion) {
return majorVersion < 12 ? new Oracle11Platform() : new OraclePlatform();
}
private DatabasePlatform mysqlVersion(int majorVersion, int minorVersion) {
if (majorVersion <= 5 && minorVersion <= 5) {
return new MySql55Platform();
@@ -215,7 +215,6 @@ class DefaultBeanLoader {
desc.contextPut(pc, id, bean);
ebi.setPersistenceContext(pc);
}
boolean draft = desc.isDraftInstance(bean);
if (embeddedOwnerIndex == -1) {
@@ -245,7 +244,6 @@ class DefaultBeanLoader {
// and put the data into the original bean
query.setUsageProfiling(false);
query.setPersistenceContext(pc);
query.setMode(mode);
query.setId(id);
@@ -1872,6 +1872,17 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return query.setId(id).findOne();
}
/**
* Create a reference with a check for the bean in the persistence context.
*/
public EntityBean createReference(Boolean readOnly, Object id, PersistenceContext pc) {
Object refBean = contextGet(pc, id);
if (refBean == null) {
refBean = createReference(readOnly, false, id, pc);
}
return (EntityBean)refBean;
}
/**
* Create a reference bean based on the id.
*/
@@ -89,7 +89,6 @@ final class BeanDescriptorCacheHelp<T> {
BeanDescriptorCacheHelp(BeanDescriptor<T> desc, SpiCacheManager cacheManager, CacheOptions cacheOptions,
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
this.desc = desc;
this.beanType = desc.rootBeanType;
this.cacheName = beanType.getSimpleName();
@@ -99,7 +98,6 @@ final class BeanDescriptorCacheHelp<T> {
this.cacheSharableBeans = cacheSharableBeans;
this.propertiesOneImported = propertiesOneImported;
this.naturalKey = cacheOptions.getNaturalKey();
if (!cacheOptions.isEnableQueryCache()) {
this.queryCache = null;
} else {
@@ -133,7 +131,6 @@ final class BeanDescriptorCacheHelp<T> {
void deriveNotifyFlags() {
cacheNotifyOnAll = (invalidateQueryCache || beanCache != null || queryCache != null);
cacheNotifyOnDelete = !cacheNotifyOnAll && isNotifyOnDeletes();
if (logger.isDebugEnabled()) {
if (cacheNotifyOnAll || cacheNotifyOnDelete) {
String notifyMode = cacheNotifyOnAll ? "All" : "Delete";
@@ -292,7 +289,6 @@ final class BeanDescriptorCacheHelp<T> {
* Try to load the bean collection from cache return true if successful.
*/
boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
if (many.isElementCollection()) {
// held as part of the bean cache so skip
return false;
@@ -307,14 +303,12 @@ final class BeanDescriptorCacheHelp<T> {
EntityBean ownerBean = bc.getOwnerBean();
EntityBeanIntercept ebi = ownerBean._ebean_getIntercept();
PersistenceContext persistenceContext = ebi.getPersistenceContext();
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
List<Object> idList = entry.getIdList();
bc.checkEmptyLazyLoad();
for (Object id : idList) {
Object refBean = targetDescriptor.createReference(readOnly, false, id, persistenceContext);
many.add(bc, (EntityBean) refBean);
many.add(bc, targetDescriptor.createReference(readOnly, id, persistenceContext));
}
return true;
}
@@ -323,7 +317,6 @@ final class BeanDescriptorCacheHelp<T> {
* Put the beanCollection into the cache.
*/
void manyPropPut(BeanPropertyAssocMany<?> many, Object details, Object parentId) {
if (many.isElementCollection()) {
CachedBeanData data = (CachedBeanData) beanCache.get(parentId);
if (data != null) {
@@ -351,7 +344,6 @@ final class BeanDescriptorCacheHelp<T> {
}
void cachePutManyIds(Object parentId, String manyName, CachedManyIds entry) {
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, manyName);
if (manyLog.isDebugEnabled()) {
manyLog.debug(" PUT {}({}).{} - ids:{}", cacheName, parentId, manyName, entry);
@@ -360,7 +352,6 @@ final class BeanDescriptorCacheHelp<T> {
}
private CachedManyIds createManyIds(BeanPropertyAssocMany<?> many, Object details) {
Collection<?> actualDetails = BeanCollectionUtil.getActualDetails(details);
if (actualDetails == null) {
return null;
@@ -378,7 +369,6 @@ final class BeanDescriptorCacheHelp<T> {
* Hit the bean cache with the given ids returning the hits.
*/
BeanCacheResult<T> cacheIdLookup(PersistenceContext context, Collection<?> ids) {
Set<Object> keys = new HashSet<>(ids.size());
for (Object id : ids) {
keys.add(desc.cacheKey(id));
@@ -395,7 +385,6 @@ final class BeanDescriptorCacheHelp<T> {
T bean = convertToBean(entry.getKey(), false, context, cachedBeanData);
result.add(bean, desc.getBeanId(bean));
}
return result;
}
@@ -403,14 +392,12 @@ final class BeanDescriptorCacheHelp<T> {
* Use natural keys to hit the bean cache and return resulting hits.
*/
BeanCacheResult<T> naturalKeyLookup(PersistenceContext context, Set<Object> keys) {
if (context == null) {
context = new DefaultPersistenceContext();
}
// naturalKey -> Id map
Map<Object, Object> naturalKeyMap = naturalKeyCache.getAll(keys);
if (natLog.isTraceEnabled()) {
natLog.trace(" MLOOKUP {}({}) - hits:{}", cacheName, keys, naturalKeyMap);
}
@@ -433,15 +420,12 @@ final class BeanDescriptorCacheHelp<T> {
}
// process the hits into beans etc
for (Map.Entry<Object, Object> entry : beanDataMap.entrySet()) {
Object id = entry.getKey();
CachedBeanData cachedBeanData = (CachedBeanData) entry.getValue();
T bean = convertToBean(id, false, context, cachedBeanData);
Object naturalKey = reverseMap.get(id);
result.add(bean, naturalKey);
}
return result;
}
@@ -452,7 +436,6 @@ final class BeanDescriptorCacheHelp<T> {
if (context == null) {
context = new DefaultPersistenceContext();
}
// Not using a loadContext for beans coming out of L2 cache
// so that means no batch lazy loading for these beans
EntityBean entityBean = (EntityBean) bean;
@@ -522,7 +505,6 @@ final class BeanDescriptorCacheHelp<T> {
* Put a bean into the bean cache.
*/
void beanCachePut(EntityBean bean) {
if (desc.inheritInfo != null) {
desc.descOf(bean.getClass()).cacheBeanPutDirect(bean);
} else {
@@ -531,7 +513,6 @@ final class BeanDescriptorCacheHelp<T> {
}
void beanCachePutAllDirect(Collection<EntityBean> beans) {
Map<Object, Object> natKeys = null;
if (naturalKey != null) {
natKeys = new LinkedHashMap<>();
@@ -566,15 +547,12 @@ final class BeanDescriptorCacheHelp<T> {
* Put the bean into the bean cache.
*/
void beanCachePutDirect(EntityBean bean) {
CachedBeanData beanData = beanExtractData(desc, bean);
String key = desc.cacheKeyForBean(bean);
if (beanLog.isDebugEnabled()) {
beanLog.debug(" PUT {}({}) data:{}", cacheName, key, beanData);
}
getBeanCache().put(key, beanData);
if (naturalKey != null) {
String naturalKey = calculateNaturalKey(beanData);
if (naturalKey != null) {
@@ -618,7 +596,6 @@ final class BeanDescriptorCacheHelp<T> {
* Return a bean from the bean cache.
*/
private T beanCacheGetInternal(String key, Boolean readOnly, PersistenceContext context) {
CachedBeanData data = (CachedBeanData) getBeanCache().get(key);
if (data == null) {
if (beanLog.isTraceEnabled()) {
@@ -646,7 +623,6 @@ final class BeanDescriptorCacheHelp<T> {
return (T) bean;
}
}
return (T) loadBean(id, readOnly, data, context);
}
@@ -654,7 +630,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the entity bean taking into account inheritance.
*/
private EntityBean loadBean(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
String discValue = data.getDiscValue();
if (discValue == null) {
return loadBeanDirect(id, readOnly, data, context);
@@ -674,7 +649,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the entity bean from cache data given this is the root bean type.
*/
EntityBean loadBeanDirect(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
id = desc.convertId(id);
EntityBean bean = null;
if (context == null) {
@@ -682,7 +656,6 @@ final class BeanDescriptorCacheHelp<T> {
} else {
bean = (EntityBean) desc.contextGet(context, id);
}
if (bean == null) {
bean = desc.createEntityBean();
desc.setId(id, bean);
@@ -698,7 +671,6 @@ final class BeanDescriptorCacheHelp<T> {
}
CachedBeanDataToBean.load(desc, bean, data, context);
if (desc.isReadAuditing()) {
desc.readAuditBean("l2", "", bean);
}
@@ -709,7 +681,6 @@ final class BeanDescriptorCacheHelp<T> {
* Load the embedded bean checking for inheritance.
*/
EntityBean embeddedBeanLoad(CachedBeanData data, PersistenceContext context) {
String discValue = data.getDiscValue();
if (discValue == null) {
return embeddedBeanLoadDirect(data, context);
@@ -746,25 +717,20 @@ final class BeanDescriptorCacheHelp<T> {
* Load a batch of entities from L2 bean cache checking the lazy loaded property is loaded.
*/
Set<EntityBeanIntercept> beanCacheLoadAll(List<EntityBeanIntercept> list, PersistenceContext context, int lazyLoadProperty, String propertyName) {
Map<Object, EntityBeanIntercept> ebis = new HashMap<>();
for (EntityBeanIntercept ebi : list) {
ebis.put(desc.cacheKeyForBean(ebi.getOwner()), ebi);
}
Map<Object, Object> hits = getBeanCache().getAll(ebis.keySet());
if (beanLog.isTraceEnabled()) {
beanLog.trace(" MLOAD {}({}) - got hits ({})", cacheName, ebis.keySet(), hits.size());
}
Set<EntityBeanIntercept> loaded = new HashSet<>();
Iterator<Map.Entry<Object, Object>> iterator = hits.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Object, Object> hit = iterator.next();
Object key = hit.getKey();
EntityBeanIntercept ebi = ebis.remove(key);
CachedBeanData cacheData = (CachedBeanData) hit.getValue();
@@ -774,7 +740,6 @@ final class BeanDescriptorCacheHelp<T> {
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
}
iterator.remove();
} else {
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
loaded.add(ebi);
@@ -783,11 +748,9 @@ final class BeanDescriptorCacheHelp<T> {
}
}
}
if (!ebis.isEmpty() && beanLog.isTraceEnabled()) {
beanLog.trace(" load {}({}) - cache miss", cacheName, ebis.keySet());
}
return loaded;
}
@@ -795,7 +758,6 @@ final class BeanDescriptorCacheHelp<T> {
* Returns true if it managed to populate/load the single bean from the cache.
*/
boolean beanCacheLoad(EntityBean bean, EntityBeanIntercept ebi, String key, PersistenceContext context) {
CachedBeanData cacheData = (CachedBeanData) getBeanCache().get(key);
if (cacheData == null) {
if (beanLog.isTraceEnabled()) {
@@ -810,7 +772,6 @@ final class BeanDescriptorCacheHelp<T> {
}
return false;
}
CachedBeanDataToBean.load(desc, bean, cacheData, context);
if (beanLog.isDebugEnabled()) {
beanLog.debug(" LOAD {}({}) - hit", cacheName, key);
@@ -932,7 +893,6 @@ final class BeanDescriptorCacheHelp<T> {
* Apply changes to the bean cache entry.
*/
void cacheBeanUpdate(String key, Map<String, Object> changes, boolean updateNaturalKey, long version) {
ServerCache cache = getBeanCache();
CachedBeanData existingData = (CachedBeanData) cache.get(key);
if (existingData != null) {
@@ -952,7 +912,6 @@ final class BeanDescriptorCacheHelp<T> {
}
cache.put(key, newData);
}
if (updateNaturalKey) {
Object oldKey = calculateNaturalKey(existingData);
if (oldKey != null) {
@@ -262,10 +262,16 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
/**
* Return true if the target side has soft delete.
*/
@Override
public boolean isTargetSoftDelete() {
return targetDescriptor.isSoftDelete();
}
@Override
public String getSoftDeletePredicate(String tableAlias) {
return targetDescriptor.getSoftDeletePredicate(tableAlias);
}
/**
* Return true if REFRESH should cascade.
*/
@@ -176,4 +176,9 @@ public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
public void setFetchPreference(int fetchPreference) {
this.fetchPreference = fetchPreference;
}
@SuppressWarnings("unchecked")
public void setTargetType(Class<?> targetType) {
this.targetType = (Class<T>)targetType;
}
}
@@ -65,19 +65,6 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
this.manyType = manyType;
}
/**
* When generics is not used for manyType you can specify via annotations.
* <p>
* Really only expect this for Scala due to a Scala compiler bug at the moment.
* Otherwise I'd probably not bother support this.
* </p>
*/
@SuppressWarnings("unchecked")
public void setTargetType(Class<?> cls) {
this.targetType = (Class<T>) cls;
}
/**
* Return the many type.
*/
@@ -0,0 +1,39 @@
package io.ebeaninternal.server.deploy.parse;
import io.ebean.config.BeanNotRegisteredException;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.BeanTable;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
abstract class AnnotationAssoc extends AnnotationParser {
final BeanDescriptorManager factory;
AnnotationAssoc(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
super(info, readConfig);
this.factory = factory;
}
void setTargetType(Class<?> targetType, DeployBeanPropertyAssoc<?> prop) {
if (!targetType.equals(void.class)) {
prop.setTargetType(targetType);
}
}
void setBeanTable(DeployBeanPropertyAssoc<?> prop) {
BeanTable assoc = getBeanTable(prop);
if (assoc == null) {
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getTargetType(), prop.getFullBeanName()));
}
prop.setBeanTable(assoc);
}
BeanTable getBeanTable(DeployBeanPropertyAssoc<?> prop) {
return factory.getBeanTable(prop.getTargetType());
}
private String errorMsgMissingBeanTable(Class<?> type, String from) {
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
}
}
@@ -5,7 +5,6 @@ import io.ebean.annotation.FetchPreference;
import io.ebean.annotation.HistoryExclude;
import io.ebean.annotation.Where;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.config.BeanNotRegisteredException;
import io.ebean.config.NamingConvention;
import io.ebean.config.TableName;
import io.ebean.core.type.ScalarType;
@@ -44,16 +43,10 @@ import static io.ebean.util.StringHelper.isNull;
/**
* Read the deployment annotation for Assoc Many beans.
*/
class AnnotationAssocManys extends AnnotationParser {
class AnnotationAssocManys extends AnnotationAssoc {
private final BeanDescriptorManager factory;
/**
* Create with the DeployInfo.
*/
AnnotationAssocManys(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
super(info, readConfig);
this.factory = factory;
super(info, readConfig, factory);
}
/**
@@ -146,15 +139,15 @@ class AnnotationAssocManys extends AnnotationParser {
JoinTable joinTable = get(prop, JoinTable.class);
if (joinTable != null) {
if (prop.isManyToMany()) {
// expected this
readJoinTable(joinTable, prop);
} else {
// OneToMany with @JoinTable
prop.setO2mJoinTable();
readJoinTable(joinTable, prop);
manyToManyDefaultJoins(prop);
}
} else if (prop.isManyToMany()) {
checkSelfManyToMany(prop);
}
if (prop.getMappedBy() != null) {
@@ -187,6 +180,12 @@ class AnnotationAssocManys extends AnnotationParser {
}
}
private void checkSelfManyToMany(DeployBeanPropertyAssocMany<?> prop) {
if (prop.getTargetType().equals(descriptor.getBeanType())) {
throw new IllegalStateException("@ManyToMany mapping for " + prop.getFullBeanName() + " requires explicit @JoinTable with joinColumns & inverseJoinColumns. Refer issue #2157");
}
}
@SuppressWarnings("unchecked")
private void readElementCollection(DeployBeanPropertyAssocMany<?> prop, ElementCollection elementCollection) {
@@ -435,13 +434,7 @@ class AnnotationAssocManys extends AnnotationParser {
prop.setInverseJoin(inverseDest);
}
private String errorMsgMissingBeanTable(Class<?> type, String from) {
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
}
private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
manyProp.setMappedBy(propAnn.mappedBy());
manyProp.setFetchType(propAnn.fetch());
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
@@ -453,7 +446,6 @@ class AnnotationAssocManys extends AnnotationParser {
}
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
manyProp.setMappedBy(propAnn.mappedBy());
manyProp.setFetchType(propAnn.fetch());
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
@@ -462,20 +454,6 @@ class AnnotationAssocManys extends AnnotationParser {
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
}
private void setTargetType(Class<?> targetType, DeployBeanPropertyAssocMany<?> prop) {
if (!targetType.equals(void.class)) {
prop.setTargetType(targetType);
}
}
private void setBeanTable(DeployBeanPropertyAssocMany<?> manyProp) {
BeanTable assoc = factory.getBeanTable(manyProp.getTargetType());
if (assoc == null) {
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(manyProp.getTargetType(), manyProp.getFullBeanName()));
}
manyProp.setBeanTable(assoc);
}
private String getM2MJoinTableName(BeanTable lhsTable, BeanTable rhsTable) {
TableName lhs = new TableName(lhsTable.getBaseTable());
@@ -33,18 +33,15 @@ import javax.validation.constraints.NotNull;
/**
* Read the deployment annotations for Associated One beans.
*/
public class AnnotationAssocOnes extends AnnotationParser {
public class AnnotationAssocOnes extends AnnotationAssoc {
private static final Logger log = LoggerFactory.getLogger(AnnotationAssocOnes.class);
private final BeanDescriptorManager factory;
/**
* Create with the deploy Info.
*/
AnnotationAssocOnes(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
super(info, readConfig);
this.factory = factory;
super(info, readConfig, factory);
}
/**
@@ -191,25 +188,11 @@ public class AnnotationAssocOnes extends AnnotationParser {
}
}
private String errorMsgMissingBeanTable(Class<?> type, String from) {
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? Does it have the @Entity annotation? See https://ebean.io/docs/trouble-shooting#not-registered";
}
private BeanTable beanTable(DeployBeanPropertyAssoc<?> prop) {
BeanTable assoc = factory.getBeanTable(prop.getPropertyType());
if (assoc == null) {
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName()));
}
return assoc;
}
private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) {
DeployBeanPropertyAssocOne<?> beanProp = (DeployBeanPropertyAssocOne<?>) prop;
private void readManyToOne(ManyToOne propAnn, DeployBeanPropertyAssocOne<?> beanProp) {
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
beanProp.setBeanTable(beanTable(beanProp));
setTargetType(propAnn.targetEntity(), beanProp);
setBeanTable(beanProp);
beanProp.setDbInsertable(true);
beanProp.setDbUpdateable(true);
beanProp.setNullable(propAnn.optional());
@@ -232,7 +215,8 @@ public class AnnotationAssocOnes extends AnnotationParser {
}
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
prop.setBeanTable(beanTable(prop));
setTargetType(propAnn.targetEntity(), prop);
setBeanTable(prop);
}
private boolean readOrphanRemoval(OneToOne property) {
@@ -261,7 +245,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
BeanTable baseBeanTable = factory.getBeanTable(info.getDescriptor().getBeanType());
String localPrimaryKey = baseBeanTable.getIdColumn();
String foreignColumn = beanTable(prop).getIdColumn();
String foreignColumn = getBeanTable(prop).getIdColumn();
prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localPrimaryKey, foreignColumn, false, false));
}
@@ -145,14 +145,6 @@ public class DeployCreateProperties {
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
Class<?> propertyType = field.getType();
ManyToOne manyToOne = AnnotationUtil.get(field, ManyToOne.class);
if (manyToOne != null) {
Class<?> tt = manyToOne.targetEntity();
if (!tt.equals(void.class)) {
propertyType = tt;
}
}
if (isSpecialScalarType(field)) {
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
}
@@ -56,7 +56,6 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
}
private void configureQuery(SpiQuery<?> query, String lazyLoadProperty) {
if (cache) {
query.setBeanCacheMode(CacheMode.ON);
}
@@ -70,7 +69,6 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
}
protected void register(EntityBeanIntercept ebi) {
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(secondaryBatchSize);
}
@@ -198,8 +196,10 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
// lazy load property was a Many
return;
}
if (context.hitCache) {
if (list.isEmpty()) {
// re-add to the batch and lazy load from DB skipping l2 cache
list.add(ebi);
} else if (context.hitCache) {
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(list, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
list.removeAll(hits);
if (list.isEmpty() || hits.contains(ebi)) {
@@ -298,18 +298,7 @@ public final class BatchControl {
// Nothing in queue to flush
return;
}
// convert entry map to array for sorting
BatchedBeanHolder[] bsArray = getBeanHolderArray();
// sort the entries by depth
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
}
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
}
executeAll();
persistedBeans.clear();
if (reset) {
beanHoldMap.clear();
@@ -323,6 +312,32 @@ public final class BatchControl {
}
}
private void executeAll() throws BatchedSqlException {
do {
// convert entry map to array for sorting
BatchedBeanHolder[] bsArray = getBeanHolderArray();
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
}
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
}
} while (!isBeanHoldersEmpty());
}
/**
* Return if all bean holders are empty.
*/
private boolean isBeanHoldersEmpty() {
for (BatchedBeanHolder beanHolder : beanHoldMap.values()) {
if (!beanHolder.isEmpty()) {
return false;
}
}
return true;
}
/**
* Return an entry for the given type description. The type description is
* typically the bean class name (or table name for MapBeans).
@@ -47,6 +47,11 @@ class BatchedBeanHolder {
*/
private ArrayList<PersistRequest> deletes;
/**
* The holder is empty
*/
private boolean empty = true;
/**
* Create a new entry with a given type and depth.
*/
@@ -63,6 +68,13 @@ class BatchedBeanHolder {
return order;
}
/**
* Returns if the BeanHolder is empty.
*/
public boolean isEmpty() {
return empty;
}
/**
* Execute all the persist requests in this entry.
* <p>
@@ -90,6 +102,7 @@ class BatchedBeanHolder {
updates = new ArrayList<>();
control.executeNow(bufferedUpdates);
}
empty = true;
}
@Override
@@ -112,9 +125,8 @@ class BatchedBeanHolder {
* Add the request to the appropriate persist list.
*/
public int append(PersistRequestBean<?> request) {
empty = false;
request.setBatched();
switch (request.getType()) {
case INSERT:
if (inserts == null) {
@@ -210,18 +210,6 @@ public class SaveManyBeans extends SaveManyBase {
return true;
}
private boolean hasNewOrDirtyBeans() {
if (collection == null) {
return false;
}
for (Object bean : collection) {
if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isNewOrDirty()) {
return true;
}
}
return false;
}
/**
* Collect the Id values of the details to remove 'missing children' for stateless updates.
*/
@@ -344,12 +332,16 @@ public class SaveManyBeans extends SaveManyBase {
transaction.depth(-1);
}
private boolean isChangedProperty() {
return parentBean._ebean_getIntercept().isChangedProperty(many.getPropertyIndex());
}
private void removeAssocManyOrphans() {
if (value == null) {
return;
}
if (!(value instanceof BeanCollection<?>)) {
if (!insertedParent && cascade && hasNewOrDirtyBeans()) {
if (!insertedParent && cascade && isChangedProperty()) {
persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
}
} else {
@@ -296,10 +296,10 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
this.cancelled = true;
if (pstmt != null) {
try {
logger.debug("Cancelling query");
pstmt.cancel();
} catch (SQLException e) {
String msg = "Error cancelling query";
throw new PersistenceException(msg, e);
throw new PersistenceException("Error cancelling query", e);
}
}
} finally {
@@ -322,7 +322,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
}
private boolean prepareBindExecuteQueryWithOption(boolean forwardOnlyHint) throws SQLException {
ResultSet resultSet = prepareResultSet(forwardOnlyHint);
if (resultSet == null) {
return false;
@@ -334,19 +333,12 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
ResultSet prepareResultSet(boolean forwardOnlyHint) throws SQLException {
lock.lock();
try {
if (cancelled || query.isCancelled()) {
// cancelled before we started
cancelled = true;
return null;
if (cancelled) {
throw new SQLException("Query cancelled");
}
startNano = System.nanoTime();
// prepare
SpiTransaction t = request.getTransaction();
profileOffset = t.profileOffset();
Connection conn = t.getInternalConnection();
if (query.isRawSql()) {
ResultSet suppliedResultSet = query.getRawSql().getResultSet();
if (suppliedResultSet != null) {
@@ -356,6 +348,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
}
}
Connection conn = t.getInternalConnection();
if (forwardOnlyHint) {
// Use forward only hints for large resultSet processing (Issue 56, MySql specific)
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
@@ -363,18 +356,13 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
} else {
pstmt = conn.prepareStatement(sql);
}
if (query.getTimeout() > 0) {
pstmt.setQueryTimeout(query.getTimeout());
}
if (query.getBufferFetchSizeHint() > 0) {
pstmt.setFetchSize(query.getBufferFetchSizeHint());
}
DataBind dataBind = queryPlan.bindEncryptedProperties(pstmt, conn);
bindLog = predicates.bind(dataBind);
// executeQuery
bindLog = predicates.bind(queryPlan.bindEncryptedProperties(pstmt, conn));
return pstmt.executeQuery();
} finally {
lock.unlock();
@@ -571,8 +571,8 @@ class CQueryBuilder {
private final CQueryPredicates predicates;
private final SqlTree select;
private final boolean updateStatement;
private final boolean distinct;
private final boolean countSingleAttribute;
private final String dbOrderBy;
private boolean useSqlLimiter;
private boolean hasWhere;
@@ -590,6 +590,7 @@ class CQueryBuilder {
this.updateStatement = updateStatement;
this.distinct = query.isDistinct() || select.isSqlDistinct();
this.dbOrderBy = predicates.getDbOrderBy();
this.countSingleAttribute = query.isCountDistinct() && query.isSingleAttribute();
}
private void appendSelect() {
@@ -601,8 +602,13 @@ class CQueryBuilder {
if (!useSqlLimiter) {
appendSelectDistinct();
}
if (query.isCountDistinct() && query.isSingleAttribute()) {
sb.append("r1.attribute_, count(*) from (select ").append(select.getSelectSql()).append(" as attribute_");
if (countSingleAttribute) {
sb.append("r1.attribute_, count(*) from (select ");
if (distinct) {
sb.append("distinct t0.");
sb.append(request.getBeanDescriptor().getIdProperty().getDbColumn()).append(", ");
}
sb.append(select.getSelectSql()).append(" as attribute_");
} else {
sb.append(select.getSelectSql());
}
@@ -621,7 +627,7 @@ class CQueryBuilder {
private void appendSelectDistinct() {
sb.append("select ");
if (distinct) {
if (distinct && !countSingleAttribute) {
if (request.isInlineCountDistinct()) {
sb.append("count(");
}
@@ -730,7 +736,7 @@ class CQueryBuilder {
sb.append(" order by ").append(dbOrderBy);
}
if (query.isCountDistinct() && query.isSingleAttribute()) {
if (countSingleAttribute) {
sb.append(") r1 group by r1.attribute_");
sb.append(toSql(query.getCountDistinctOrder()));
}
@@ -401,12 +401,6 @@ public class CQueryEngine {
if (cquery != null) {
cquery.close();
}
if (request.getQuery().isFutureFetch()) {
// end the transaction for futureFindIds
// as it had it's own transaction
logger.debug("Future fetch completed!");
request.getTransaction().end();
}
}
}
@@ -36,4 +36,13 @@ public interface STreePropertyAssoc extends STreeProperty {
*/
void setValue(EntityBean parentBean, Object contextBean);
/**
* Return true if the associated type has soft delete.
*/
boolean isTargetSoftDelete();
/**
* Return the soft delete predicate.
*/
String getSoftDeletePredicate(String tableAlias);
}
@@ -74,7 +74,6 @@ public final class SqlTreeBuilder {
* Construct for RawSql query.
*/
SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates, OrmQueryDetail queryDetail, boolean rawNoId) {
this.rawSql = true;
this.desc = request.getBeanDescriptor();
this.rawNoId = rawNoId;
@@ -97,7 +96,6 @@ public final class SqlTreeBuilder {
* to the root node.
*/
SqlTreeBuilder(String columnAliasPrefix, CQueryBuilder builder, OrmQueryRequest<?> request, CQueryPredicates predicates) {
this.rawSql = false;
this.rawNoId = false;
this.desc = request.getBeanDescriptor();
@@ -108,11 +106,9 @@ public final class SqlTreeBuilder {
this.includeJoin = query.getM2mIncludeJoin();
this.manyWhereJoins = query.getManyWhereJoins();
this.queryDetail = query.getDetail();
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.getBaseTableAlias(), temporalMode);
this.distinctOnPlatform = builder.isPlatformDistinctOn();
String fromForUpdate = builder.fromForUpdate(query);
CQueryHistorySupport historySupport = builder.getHistorySupport(query);
CQueryDraftSupport draftSupport = builder.getDraftSupport(query);
@@ -124,10 +120,8 @@ public final class SqlTreeBuilder {
* Build based on the includes and using the BeanJoinTree.
*/
public SqlTree build() {
// build the appropriate chain of SelectAdapter's
buildRoot(desc);
// build the actual String
String distinctOn = null;
String selectSql = null;
@@ -149,7 +143,6 @@ public final class SqlTreeBuilder {
}
private String buildSelectClause() {
if (rawSql) {
return "Not Used";
}
@@ -158,7 +151,6 @@ public final class SqlTreeBuilder {
}
private String buildGroupByClause() {
if (rawSql || !rootNode.isAggregation()) {
return null;
}
@@ -168,7 +160,6 @@ public final class SqlTreeBuilder {
}
private String buildDistinctOn() {
if (rawSql || !distinctOnPlatform || !sqlDistinct || Type.COUNT == query.getType()) {
return null;
}
@@ -207,7 +198,6 @@ public final class SqlTreeBuilder {
}
private String buildWhereClause() {
if (rawSql) {
return "Not Used";
}
@@ -216,7 +206,6 @@ public final class SqlTreeBuilder {
}
private String buildFromClause() {
if (rawSql) {
return "Not Used";
}
@@ -225,17 +214,13 @@ public final class SqlTreeBuilder {
}
private void buildRoot(STreeType desc) {
rootNode = buildSelectChain(null, null, desc, null);
if (!rawSql) {
alias.addJoin(queryDetail.getFetchPaths(), desc);
alias.addJoin(predicates.getPredicateIncludes(), desc);
alias.addManyWhereJoins(manyWhereJoins.getPropertyNames());
// build set of table alias
alias.buildAlias();
predicates.parseTableAlias(alias);
}
}
@@ -246,9 +231,7 @@ public final class SqlTreeBuilder {
*/
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
STreeType desc, List<SqlTreeNode> joinList) {
List<SqlTreeNode> myJoinList = new ArrayList<>();
List<STreePropertyAssocOne> extraProps = new ArrayList<>();
for (STreePropertyAssocOne one : desc.propsOne()) {
String propPrefix = SplitName.add(prefix, one.getName());
@@ -295,7 +278,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private void addManyWhereJoins(List<SqlTreeNode> myJoinList) {
Collection<PropertyJoin> includes = manyWhereJoins.getPropertyJoins();
for (PropertyJoin joinProp : includes) {
STreePropertyAssoc beanProperty = (STreePropertyAssoc) desc.findPropertyFromPath(joinProp.getProperty());
@@ -311,7 +293,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> myList, SqlTreeProperties props) {
if (prefix == null) {
buildExtraJoins(desc, myList);
@@ -340,13 +321,10 @@ public final class SqlTreeBuilder {
* already in select clause.
*/
private void buildExtraJoins(STreeType desc, List<SqlTreeNode> myList) {
if (rawSql) {
return;
}
Set<String> predicateIncludes = predicates.getPredicateIncludes();
if (predicateIncludes == null) {
return;
}
@@ -362,8 +340,7 @@ public final class SqlTreeBuilder {
// look for predicateIncludes that are not in selectIncludes and add
// them as extra joins to the query
IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes, predicateIncludes);
IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes, predicateIncludes, temporalMode);
Collection<SqlTreeNodeExtraJoin> extraJoins = extraJoinDistill.getExtraJoinRootNodes();
if (!extraJoins.isEmpty()) {
// add extra joins required to support predicates
@@ -389,7 +366,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private void addPropertyToSubQuery(SqlTreeProperties selectProps, STreeType desc, String propName) {
STreeProperty p = desc.findProperty(propName);
if (p == null) {
logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
@@ -402,13 +378,10 @@ public final class SqlTreeBuilder {
p = ((STreePropertyAssoc) p).target().findProperty(name);
}
}
selectProps.add(p);
}
private void addProperty(SqlTreeProperties selectProps, STreeType desc,
OrmQueryProperties queryProps, String propName) {
private void addProperty(SqlTreeProperties selectProps, STreeType desc, OrmQueryProperties queryProps, String propName) {
if (subQuery) {
addPropertyToSubQuery(selectProps, desc, propName);
return;
@@ -471,7 +444,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeProperties getBaseSelectPartial(STreeType desc, OrmQueryProperties queryProps) {
SqlTreeProperties selectProps = new SqlTreeProperties();
// add properties in the order in which they appear
// in the query. Gives predictable sql/properties for
@@ -502,7 +474,6 @@ public final class SqlTreeBuilder {
}
private SqlTreeProperties getBaseSelect(STreeType desc, OrmQueryProperties queryProps) {
boolean partial = queryProps != null && !queryProps.allProperties();
if (partial) {
return getBaseSelectPartial(desc, queryProps);
@@ -541,13 +512,10 @@ public final class SqlTreeBuilder {
* Return true if this many node should be included in the query.
*/
private boolean isIncludeMany(String propName, STreePropertyAssocMany manyProp) {
if (queryDetail.isJoinsEmpty()) {
return false;
}
if (queryDetail.includesPath(propName)) {
if (manyProperty != null) {
// only one many associated allowed to be included in fetch
if (logger.isDebugEnabled()) {
@@ -555,7 +523,6 @@ public final class SqlTreeBuilder {
}
return false;
}
manyProperty = manyProp;
return true;
}
@@ -571,7 +538,6 @@ public final class SqlTreeBuilder {
* </p>
*/
private boolean isIncludeBean(String prefix) {
if (queryDetail.includesPath(prefix)) {
// explicitly included
String[] splitNames = SplitName.split(prefix);
@@ -592,26 +558,20 @@ public final class SqlTreeBuilder {
*/
private static class IncludesDistiller {
private final STreeType desc;
private final Set<String> selectIncludes;
private final Set<String> predicateIncludes;
private final SpiQuery.TemporalMode temporalMode;
/**
* Contains the 'root' extra joins. We only return the roots back.
*/
private final Map<String, SqlTreeNodeExtraJoin> joinRegister = new HashMap<>();
/**
* Register of all the extra join nodes.
*/
private final Map<String, SqlTreeNodeExtraJoin> rootRegister = new HashMap<>();
private final STreeType desc;
private IncludesDistiller(STreeType desc, Set<String> selectIncludes,
Set<String> predicateIncludes) {
Set<String> predicateIncludes, SpiQuery.TemporalMode temporalMode) {
this.desc = desc;
this.selectIncludes = selectIncludes;
this.predicateIncludes = predicateIncludes;
this.temporalMode = temporalMode;
}
/**
@@ -623,26 +583,21 @@ public final class SqlTreeBuilder {
* </p>
*/
private Collection<SqlTreeNodeExtraJoin> getExtraJoinRootNodes() {
String[] extras = findExtras();
if (extras.length == 0) {
return rootRegister.values();
}
// sort so we process only getting the leaves
// excluding nodes between root and the leaf
Arrays.sort(extras);
// reverse order so get the leaves first...
for (String extra : extras) {
createExtraJoin(extra);
}
return rootRegister.values();
}
private void createExtraJoin(String includeProp) {
SqlTreeNodeExtraJoin extraJoin = createJoinLeaf(includeProp);
if (extraJoin != null) {
// add the extra join...
@@ -650,7 +605,6 @@ public final class SqlTreeBuilder {
// find root of this extra join... linking back to the
// parents (creating the tree) as it goes.
SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
// register the root because these are the only ones we
// return back.
rootRegister.put(root.getName(), root);
@@ -661,12 +615,11 @@ public final class SqlTreeBuilder {
* Create a SqlTreeNodeExtraJoin, register and return it.
*/
private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
ExtraJoin extra = desc.extraJoin(propertyName);
if (extra == null) {
return null;
} else {
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany());
SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany(), temporalMode);
joinRegister.put(propertyName, extraJoin);
return extraJoin;
}
@@ -713,9 +666,7 @@ public final class SqlTreeBuilder {
* by the select.
*/
private String[] findExtras() {
List<String> extras = new ArrayList<>();
for (String predProp : predicateIncludes) {
if (!selectIncludes.contains(predProp)) {
extras.add(predProp);
@@ -24,19 +24,17 @@ import java.util.Set;
class SqlTreeNodeExtraJoin implements SqlTreeNode {
private final STreePropertyAssoc assocBeanProperty;
private final SpiQuery.TemporalMode temporalMode;
private final String prefix;
private final boolean manyJoin;
private final boolean pathContainsMany;
private List<SqlTreeNodeExtraJoin> children;
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany) {
SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany, SpiQuery.TemporalMode temporalMode) {
this.prefix = prefix;
this.assocBeanProperty = assocBeanProperty;
this.pathContainsMany = pathContainsMany;
this.temporalMode = temporalMode;
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
}
@@ -113,9 +111,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
@Override
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
boolean manyToMany = false;
if (assocBeanProperty instanceof STreePropertyAssocMany) {
STreePropertyAssocMany manyProp = (STreePropertyAssocMany) assocBeanProperty;
if (manyProp.hasJoinTable()) {
@@ -144,15 +140,16 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
assocBeanProperty.appendFrom(ctx, joinType);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
if (assocBeanProperty.isTargetSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
ctx.append(" and ").append(assocBeanProperty.getSoftDeletePredicate(ctx.getTableAlias(prefix)));
}
}
if (children != null) {
if (manyJoin || pathContainsMany) {
// if AUTO then make all descendants use OUTER JOIN
joinType = joinType.autoToOuter();
}
for (SqlTreeNodeExtraJoin child : children) {
child.appendFrom(ctx, joinType);
}
@@ -751,7 +751,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public NaturalKeyQueryData<T> naturalKey() {
if (whereExpressions == null) {
return null;
}
@@ -767,7 +766,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return null;
}
}
return data;
}
@@ -815,7 +813,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
copy.m2mIncludeJoin = m2mIncludeJoin;
copy.profilingListener = profilingListener;
copy.profileLocation = profileLocation;
copy.baseTable = baseTable;
copy.rootTableAlias = rootTableAlias;
copy.distinct = distinct;
@@ -1100,7 +1097,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public ObjectGraphNode setOrigin(CallOrigin callOrigin) {
// create a 'origin' which links this query to the profiling information
ObjectGraphOrigin o = new ObjectGraphOrigin(calculateOriginQueryHash(), callOrigin, beanType.getName());
parentNode = new ObjectGraphNode(o, null);
@@ -1241,7 +1237,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/
@Override
public CQueryPlanKey prepare(SpiOrmQueryRequest<T> request) {
prepareExpressions(request);
prepareForPaging();
queryPlanKey = createQueryPlanKey();
@@ -1252,7 +1247,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* Prepare the expressions (compile sub-queries etc).
*/
private void prepareExpressions(BeanQueryRequest<?> request) {
if (whereExpressions != null) {
whereExpressions.prepareExpression(request);
}
@@ -1267,7 +1261,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* case, this is not a distinct query
*/
private void prepareForPaging() {
// add the rawSql statement - if any
if (orderByIsEmpty()) {
if (rawSql != null && rawSql.getSql() != null) {
@@ -1678,7 +1671,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this;
}
}
if (bindParams == null) {
bindParams = new BindParams();
}
@@ -1972,7 +1964,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
if (namedParams == null) {
namedParams = new HashMap<>();
}
return namedParams.computeIfAbsent(name, ONamedParam::new);
}
@@ -2066,8 +2057,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
public void cancel() {
lock.lock();
try {
cancelled = true;
if (cancelableQuery != null) {
if (!cancelled && cancelableQuery != null) {
cancelled = true;
cancelableQuery.cancel();
}
} finally {
@@ -2095,7 +2086,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
*/
@Override
public Set<String> validate(BeanType<T> desc) {
SpiExpressionValidation validation = new SpiExpressionValidation(desc);
if (whereExpressions != null) {
whereExpressions.validate(validation);
@@ -3,6 +3,9 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.ExpressionList;
import io.ebean.ProfileLocation;
import io.ebean.UpdateQuery;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
/**
* Default implementation of UpdateQuery.
@@ -10,23 +13,30 @@ import io.ebean.UpdateQuery;
public class DefaultUpdateQuery<T> implements UpdateQuery<T> {
private final OrmUpdateProperties values = new OrmUpdateProperties();
private final DefaultOrmQuery<T> query;
private final BeanDescriptor<T> descriptor;
public DefaultUpdateQuery(DefaultOrmQuery<T> query) {
this.query = query;
this.descriptor = query.getBeanDescriptor();
query.setUpdateProperties(values);
}
@Override
public UpdateQuery<T> set(String property, Object value) {
values.set(property, value);
if (value == null) {
values.setNull(property);
} else {
final BeanProperty beanProperty = descriptor.getBeanProperty(property);
final ScalarType<Object> scalarType = (beanProperty == null) ? null: beanProperty.getScalarType();
values.set(property, value, scalarType);
}
return this;
}
@Override
public UpdateQuery<T> setNull(String property) {
values.set(property, null);
values.setNull(property);
return this;
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.DeployParser;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.type.DataBind;
@@ -53,9 +54,11 @@ public class OrmUpdateProperties {
private static class SimpleValue extends Value {
final Object value;
final ScalarType<Object> scalarType;
SimpleValue(Object value) {
SimpleValue(Object value, ScalarType<Object> scalarType) {
this.value = value;
this.scalarType = scalarType;
}
@Override
@@ -70,7 +73,11 @@ public class OrmUpdateProperties {
@Override
public void bind(Binder binder, DataBind dataBind) throws SQLException {
binder.bindObject(dataBind, value);
if (scalarType != null) {
scalarType.bind(dataBind, value);
} else {
binder.bindObject(dataBind, value);
}
dataBind.append(value).append(",");
}
}
@@ -115,16 +122,12 @@ public class OrmUpdateProperties {
*/
private final LinkedHashMap<String, Value> values = new LinkedHashMap<>();
/**
* Normal set property.
*/
public void set(String propertyName, Object value) {
if (value == null) {
values.put(propertyName, NULL_VALUE);
public void set(String propertyName, Object value, ScalarType<Object> scalarType) {
values.put(propertyName, new SimpleValue(value, scalarType));
}
} else {
values.put(propertyName, new SimpleValue(value));
}
public void setNull(String propertyName) {
values.put(propertyName, NULL_VALUE);
}
/**
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-12-07T09:40:50.461215Z
-- Generated by ebean unknown at 2021-02-12T03:32:14.253435800Z
create table asimple_bean (
id bigint generated by default as identity not null,
name varchar(255),
@@ -486,6 +486,13 @@ create table child_person (
constraint pk_child_person primary key (identifier)
);
create table child_with_cache (
id bigint generated by default as identity not null,
name varchar(255),
address varchar(255),
constraint pk_child_with_cache primary key (id)
);
create table cke_client (
cod_cpny integer not null,
cod_client varchar(100) not null,
@@ -1168,6 +1175,12 @@ create table ebasic_json_unmapped (
constraint pk_ebasic_json_unmapped primary key (id)
);
create table e_basic_log (
id bigint generated by default as identity not null,
name varchar(255),
constraint pk_e_basic_log primary key (id)
);
create table e_basic_ndc (
id integer generated by default as identity not null,
name varchar(255),
@@ -1227,6 +1240,14 @@ create table e_basic_with_ex (
constraint pk_e_basic_with_ex primary key (id)
);
create table e_basic_withlog (
id bigint generated by default as identity not null,
name varchar(255),
deleted boolean default false not null,
version bigint not null,
constraint pk_e_basic_withlog primary key (id)
);
create table e_basicverucon (
id integer generated by default as identity not null,
name varchar(127),
@@ -2256,6 +2277,29 @@ create table looney (
constraint pk_looney primary key (id)
);
create table m2_mcache_child (
id integer generated by default as identity not null,
name varchar(255),
constraint pk_m2_mcache_child primary key (id)
);
create table m2_mcache_master (
id integer generated by default as identity not null,
constraint pk_m2_mcache_master primary key (id)
);
create table m2mcache_set1 (
m2_mcache_master_id integer not null,
m2_mcache_child_id integer not null,
constraint pk_m2mcache_set1 primary key (m2_mcache_master_id,m2_mcache_child_id)
);
create table m2mcache_set2 (
m2_mcache_master_id integer not null,
m2_mcache_child_id integer not null,
constraint pk_m2mcache_set2 primary key (m2_mcache_master_id,m2_mcache_child_id)
);
create table maddress (
id uuid not null,
street varchar(255),
@@ -3230,6 +3274,19 @@ create table e_save_test_c (
constraint pk_e_save_test_c primary key (id)
);
create table parent_a (
id bigint generated by default as identity not null,
child_id bigint,
name varchar(255),
constraint pk_parent_a primary key (id)
);
create table parent_b (
id bigint generated by default as identity not null,
child_id bigint,
constraint pk_parent_b primary key (id)
);
create table parent_person (
identifier integer generated by default as identity not null,
name varchar(255),
@@ -3361,6 +3418,15 @@ create table person_cache_info (
constraint pk_person_cache_info primary key (person_id)
);
create table persona (
id bigint generated by default as identity not null,
persona varchar(255),
person_oid bigint,
version integer not null,
constraint uq_persona_person_oid unique (person_oid),
constraint pk_persona primary key (id)
);
create table phones (
id bigint generated by default as identity not null,
phone_number varchar(7) not null,
@@ -4574,6 +4640,18 @@ alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_at
create index ix_looney_tune_id on looney (tune_id);
alter table looney add constraint fk_looney_tune_id foreign key (tune_id) references tune (id) on delete restrict on update restrict;
create index ix_m2mcache_set1_m2_mcache_master on m2mcache_set1 (m2_mcache_master_id);
alter table m2mcache_set1 add constraint fk_m2mcache_set1_m2_mcache_master foreign key (m2_mcache_master_id) references m2_mcache_master (id) on delete restrict on update restrict;
create index ix_m2mcache_set1_m2_mcache_child on m2mcache_set1 (m2_mcache_child_id);
alter table m2mcache_set1 add constraint fk_m2mcache_set1_m2_mcache_child foreign key (m2_mcache_child_id) references m2_mcache_child (id) on delete restrict on update restrict;
create index ix_m2mcache_set2_m2_mcache_master on m2mcache_set2 (m2_mcache_master_id);
alter table m2mcache_set2 add constraint fk_m2mcache_set2_m2_mcache_master foreign key (m2_mcache_master_id) references m2_mcache_master (id) on delete restrict on update restrict;
create index ix_m2mcache_set2_m2_mcache_child on m2mcache_set2 (m2_mcache_child_id);
alter table m2mcache_set2 add constraint fk_m2mcache_set2_m2_mcache_child foreign key (m2_mcache_child_id) references m2_mcache_child (id) on delete restrict on update restrict;
create index ix_mcontact_customer_id on mcontact (customer_id);
alter table mcontact add constraint fk_mcontact_customer_id foreign key (customer_id) references mcustomer (id) on delete restrict on update restrict;
@@ -4796,6 +4874,12 @@ alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_paren
create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id);
alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict;
create index ix_parent_a_child_id on parent_a (child_id);
alter table parent_a add constraint fk_parent_a_child_id foreign key (child_id) references child_with_cache (id) on delete restrict on update restrict;
create index ix_parent_b_child_id on parent_b (child_id);
alter table parent_b add constraint fk_parent_b_child_id foreign key (child_id) references child_with_cache (id) on delete restrict on update restrict;
create index ix_parent_person_some_bean_id on parent_person (some_bean_id);
alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict;
@@ -4829,6 +4913,8 @@ alter table person add constraint fk_person_default_address_oid foreign key (def
create index ix_person_cache_email_person_info_person_id on person_cache_email (person_info_person_id);
alter table person_cache_email add constraint fk_person_cache_email_person_info_person_id foreign key (person_info_person_id) references person_cache_info (person_id) on delete restrict on update restrict;
alter table persona add constraint fk_persona_person_oid foreign key (person_oid) references person (oid) on delete restrict on update restrict;
create index ix_phones_person_id on phones (person_id);
alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict;
+41 -1
View File
@@ -1,4 +1,4 @@
-- Generated by ebean unknown at 2020-12-07T09:40:50.461215Z
-- Generated by ebean unknown at 2021-02-12T03:32:14.253435800Z
alter table bar drop constraint if exists fk_bar_foo_id;
drop index if exists ix_bar_foo_id;
@@ -417,6 +417,18 @@ drop index if exists ix_la_attr_value_attribute_attribute;
alter table looney drop constraint if exists fk_looney_tune_id;
drop index if exists ix_looney_tune_id;
alter table m2mcache_set1 drop constraint if exists fk_m2mcache_set1_m2_mcache_master;
drop index if exists ix_m2mcache_set1_m2_mcache_master;
alter table m2mcache_set1 drop constraint if exists fk_m2mcache_set1_m2_mcache_child;
drop index if exists ix_m2mcache_set1_m2_mcache_child;
alter table m2mcache_set2 drop constraint if exists fk_m2mcache_set2_m2_mcache_master;
drop index if exists ix_m2mcache_set2_m2_mcache_master;
alter table m2mcache_set2 drop constraint if exists fk_m2mcache_set2_m2_mcache_child;
drop index if exists ix_m2mcache_set2_m2_mcache_child;
alter table mcontact drop constraint if exists fk_mcontact_customer_id;
drop index if exists ix_mcontact_customer_id;
@@ -639,6 +651,12 @@ drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_parent;
alter table rawinherit_parent_rawinherit_data drop constraint if exists fk_rawinherit_parent_rawinherit_data_rawinherit_data;
drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_data;
alter table parent_a drop constraint if exists fk_parent_a_child_id;
drop index if exists ix_parent_a_child_id;
alter table parent_b drop constraint if exists fk_parent_b_child_id;
drop index if exists ix_parent_b_child_id;
alter table parent_person drop constraint if exists fk_parent_person_some_bean_id;
drop index if exists ix_parent_person_some_bean_id;
@@ -672,6 +690,8 @@ drop index if exists ix_person_default_address_oid;
alter table person_cache_email drop constraint if exists fk_person_cache_email_person_info_person_id;
drop index if exists ix_person_cache_email_person_info_person_id;
alter table persona drop constraint if exists fk_persona_person_oid;
alter table phones drop constraint if exists fk_phones_person_id;
drop index if exists ix_phones_person_id;
@@ -970,6 +990,8 @@ drop table if exists e_save_test_d;
drop table if exists child_person;
drop table if exists child_with_cache;
drop table if exists cke_client;
drop table if exists cke_user;
@@ -1131,6 +1153,8 @@ drop table if exists ebasic_json_node_varchar;
drop table if exists ebasic_json_unmapped;
drop table if exists e_basic_log;
drop table if exists e_basic_ndc;
drop table if exists ebasic_no_sdchild;
@@ -1145,6 +1169,8 @@ drop table if exists e_basic_withlife;
drop table if exists e_basic_with_ex;
drop table if exists e_basic_withlog;
drop table if exists e_basicverucon;
drop table if exists ecache_child;
@@ -1463,6 +1489,14 @@ drop table if exists la_attr_value_attribute;
drop table if exists looney;
drop table if exists m2_mcache_child;
drop table if exists m2_mcache_master;
drop table if exists m2mcache_set1;
drop table if exists m2mcache_set2;
drop table if exists maddress;
drop table if exists mcontact;
@@ -1715,6 +1749,10 @@ drop table if exists rawinherit_parent_rawinherit_data;
drop table if exists e_save_test_c;
drop table if exists parent_a;
drop table if exists parent_b;
drop table if exists parent_person;
drop table if exists c_participation;
@@ -1745,6 +1783,8 @@ drop table if exists person_cache_email;
drop table if exists person_cache_info;
drop table if exists persona;
drop table if exists phones;
drop table if exists e_position;
@@ -16,7 +16,7 @@ public class TestManyOneInterface extends BaseTestCase {
ResetBasicData.reset();
IAddress a = new Address();
IAddress a = new Address("hello");
IPerson p = new Person();
@@ -0,0 +1,137 @@
package org.tests.batchload;
import io.ebean.BaseTestCase;
import io.ebean.BeanState;
import io.ebean.DB;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
public class TestBeanState extends BaseTestCase {
@Test
public void test() {
ResetBasicData.reset();
List<Customer> custs = DB.find(Customer.class).findList();
Customer customer = DB.find(Customer.class).setId(custs.get(0).getId()).select("name")
.setUseCache(false)
.findOne();
BeanState beanState = DB.getBeanState(customer);
assertFalse(beanState.isNew());
assertFalse(beanState.isDirty());
assertFalse(beanState.isNewOrDirty());
assertNotNull(beanState.getLoadedProps());
customer.setName("dirtyNameProp");
assertTrue(beanState.isDirty());
assertThat(beanState.getChangedProps()).containsOnly("name");
EntityBeanIntercept ebi = ((EntityBean) customer)._ebean_getIntercept();
boolean[] dirtyProperties = ebi.getDirtyProperties();
for (int i = 0; i < dirtyProperties.length; i++) {
if (dirtyProperties[i]) {
String dirtyPropertyName = ebi.getProperty(i);
assertEquals("name", dirtyPropertyName);
}
}
customer.setStatus(Customer.Status.INACTIVE);
assertTrue(beanState.isDirty());
assertThat(beanState.getChangedProps()).containsOnly("name", "status");
}
@Test
public void setDisableLazyLoad_expect_lazyLoadingDisabled() {
ResetBasicData.reset();
List<Customer> custs = DB.find(Customer.class).order("id").findList();
Customer customer = DB.find(Customer.class)
.setId(custs.get(0).getId())
.select("id")
.setUseCache(false)
.findOne();
BeanState beanState = DB.getBeanState(customer);
beanState.setDisableLazyLoad(true);
assertNull(customer.getName());
}
@Test
public void getChangedProps_when_setManyProperty() {
ResetBasicData.reset();
Customer customer = DB.find(Customer.class).order("id").setMaxRows(1).findOne();
BeanState beanState = DB.getBeanState(customer);
assertThat(beanState.getChangedProps()).isEmpty();
customer.setContacts(new ArrayList<>());
assertThat(beanState.getChangedProps()).containsOnly("contacts");
}
@Test
public void getChangedProps_when_setManyProperty_onNewBean() {
Customer customer = new Customer();
BeanState beanState = DB.getBeanState(customer);
assertThat(beanState.getChangedProps()).isEmpty();
// when new state, then loaded
customer.setContacts(new ArrayList<>());
assertThat(beanState.getChangedProps()).isEmpty();
assertThat(beanState.getLoadedProps()).containsOnly("contacts");
// set loaded state, then marked as changed
beanState.setLoaded();
customer.setContacts(new ArrayList<>());
assertThat(beanState.getLoadedProps()).containsOnly("contacts");
assertThat(beanState.getChangedProps()).containsOnly("contacts");
}
@Test(expected = IllegalStateException.class)
public void readOnly_when_setManyProperty() {
Customer customer = new Customer();
customer.setContacts(new ArrayList<>());
BeanState beanState = DB.getBeanState(customer);
beanState.setLoaded();
beanState.setReadOnly(true);
// act, try to mutate read only bean
customer.setContacts(new ArrayList<>());
}
@Test(expected = IllegalStateException.class)
public void readOnly_when_setProperty() {
Customer customer = new Customer();
customer.setName("a");
BeanState beanState = DB.getBeanState(customer);
beanState.setLoaded();
beanState.setReadOnly(true);
// act, try to mutate read only bean
customer.setName("b");
}
}
@@ -1,74 +0,0 @@
package org.tests.batchload;
import io.ebean.BaseTestCase;
import io.ebean.BeanState;
import io.ebean.Ebean;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
public class TestLoadOnDirty extends BaseTestCase {
@Test
public void test() {
ResetBasicData.reset();
List<Customer> custs = Ebean.find(Customer.class).findList();
Customer customer = Ebean.find(Customer.class).setId(custs.get(0).getId()).select("name")
.setUseCache(false)
.findOne();
BeanState beanState = Ebean.getBeanState(customer);
Assert.assertTrue(!beanState.isNew());
Assert.assertTrue(!beanState.isDirty());
Assert.assertTrue(!beanState.isNewOrDirty());
Assert.assertNotNull(beanState.getLoadedProps());
customer.setName("dirtyNameProp");
Assert.assertTrue(beanState.isDirty());
Assert.assertTrue(beanState.getChangedProps().contains("name"));
Assert.assertEquals(1, beanState.getChangedProps().size());
EntityBeanIntercept ebi = ((EntityBean) customer)._ebean_getIntercept();
boolean[] dirtyProperties = ebi.getDirtyProperties();
for (int i = 0; i < dirtyProperties.length; i++) {
if (dirtyProperties[i]) {
String dirtyPropertyName = ebi.getProperty(i);
Assert.assertEquals("name", dirtyPropertyName);
}
}
customer.setStatus(Customer.Status.INACTIVE);
Assert.assertTrue(beanState.isDirty());
Assert.assertTrue(beanState.getChangedProps().contains("status"));
Assert.assertTrue(beanState.getChangedProps().contains("name"));
Assert.assertEquals(2, beanState.getChangedProps().size());
}
@Test
public void testDisableLazyLoad() {
ResetBasicData.reset();
List<Customer> custs = Ebean.find(Customer.class).order("id").findList();
Customer customer = Ebean.find(Customer.class)
.setId(custs.get(0).getId())
.select("id")
.setUseCache(false)
.findOne();
BeanState beanState = Ebean.getBeanState(customer);
beanState.setDisableLazyLoad(true);
Assert.assertNull(customer.getName());
}
}
@@ -0,0 +1,78 @@
package org.tests.cache;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.tests.model.cache.M2MCacheChild;
import org.tests.model.cache.M2MCacheMaster;
import io.ebean.BaseTestCase;
import io.ebean.DB;
public class TestM2MCache extends BaseTestCase {
@Test
public void testM2MWithCache() throws Exception {
M2MCacheChild cld = new M2MCacheChild();
cld.setName("test");
cld.setId(1);
DB.save(cld);
M2MCacheMaster cfg = new M2MCacheMaster();
cfg.setId(42);
cfg.getSet1().add(cld);
cfg.getSet2().add(cld);
DB.save(cfg);
// find master and access set1 + set2.
// lazy load something from set1
M2MCacheMaster cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
// do it again
cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
// do it again
cfg1 = DB.find(M2MCacheMaster.class, 42);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
}
@Test
public void testM2MWithCacheMinimal() throws Exception {
M2MCacheChild cld = new M2MCacheChild();
cld.setName("test");
cld.setId(2);
DB.save(cld);
M2MCacheMaster cfg = new M2MCacheMaster();
cfg.setId(43);
cfg.getSet1().add(cld);
cfg.getSet2().add(cld);
DB.save(cfg);
DB.find(M2MCacheMaster.class, 43);
M2MCacheMaster cfg1 = DB.find(M2MCacheMaster.class, 43);
cfg1.getSet2().size();
cfg1 = DB.find(M2MCacheMaster.class, 43);
cfg1.getSet1().size();
cfg1.getSet2().size();
assertThat(cfg1.getSet1().iterator().next().getName()).isEqualTo("test");
}
}
@@ -6,6 +6,8 @@ import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
@@ -26,6 +28,23 @@ public class TestOnlyKillOrphans extends BaseTestCase {
DB.delete(check);
}
@Test
public void test2() {
final COOne one = setup();
assertThat(one.getChildren()).hasSize(2);
one.getChildren().add(new COOneMany("_M1"));
DB.save(one);
// assert
COOne check = DB.find(COOne.class, one.getId());
assertThat(check.getChildren().stream().map(it -> it.getName()).sorted().collect(Collectors.toList()))
.isEqualTo(Stream.of("M1", "M2", "_M1").sorted().collect(Collectors.toList()));
DB.delete(check);
}
private COOne setup() {
COOne one = new COOne("P0");
one.setChildren(createManies("M1", "M2"));
@@ -1,7 +1,7 @@
package org.tests.json;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.Platform;
import io.ebean.text.TextException;
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertTrue;
public class TestDbJson_List extends BaseTestCase {
private EBasicJsonList bean = new EBasicJsonList();
private final EBasicJsonList bean = new EBasicJsonList();
private EBasicJsonList found;
@@ -57,9 +57,9 @@ public class TestDbJson_List extends BaseTestCase {
bean.getBeanMap().put("key0", new PlainBean("k0", 90));
bean.getBeanMap().put("key1", new PlainBean("k1", 91));
Ebean.save(bean);
DB.save(bean);
found = Ebean.find(EBasicJsonList.class, bean.getId());
found = DB.find(EBasicJsonList.class, bean.getId());
assertThat(found.getTags()).containsExactly("one", "two");
assertTrue(found.getFlags().contains(42L));
@@ -81,7 +81,7 @@ public class TestDbJson_List extends BaseTestCase {
//@Test//(dependsOnMethods = "insert")
public void json_parse_format() {
String asJson = Ebean.json().toJson(found);
String asJson = DB.json().toJson(found);
assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]");
assertThat(asJson).contains("\"flags\":[42,43,44]");
assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\"");
@@ -90,7 +90,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(asJson).contains("\"beanMap\":{");
assertThat(asJson).contains("\"id\":");
EBasicJsonList fromJson = Ebean.json().toBean(EBasicJsonList.class, asJson);
EBasicJsonList fromJson = DB.json().toBean(EBasicJsonList.class, asJson);
assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getId(), fromJson.getId());
assertEquals(found.getName(), fromJson.getName());
@@ -109,7 +109,7 @@ public class TestDbJson_List extends BaseTestCase {
found.setName("mod");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -122,7 +122,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getTags().add("three");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -135,7 +135,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getFlags().remove(42L);
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -150,7 +150,7 @@ public class TestDbJson_List extends BaseTestCase {
found.getBeanMap().remove("key0");
LoggedSqlCollector.start();
Ebean.save(found);
DB.save(found);
List<String> sql = LoggedSqlCollector.stop();
// we don't update the phone numbers (as they are not dirty)
@@ -166,13 +166,13 @@ public class TestDbJson_List extends BaseTestCase {
bean.setTags(null);
bean.setBeanMap(null);
Ebean.save(bean);
DB.save(bean);
EBasicJsonList found = Ebean.find(EBasicJsonList.class, bean.getId());
EBasicJsonList found = DB.find(EBasicJsonList.class, bean.getId());
assertNull(found.getPlainBean());
String asJson = Ebean.json().toJson(found);
String asJson = DB.json().toJson(found);
assertNotNull(asJson);
}
@@ -186,17 +186,16 @@ public class TestDbJson_List extends BaseTestCase {
plainBean.setName("Blubb");
bean.getBeanMap().put("bla", plainBean);
Ebean.save(bean);
DB.save(bean);
// set some invalid JSON content into DB
Ebean.update(EBasicJsonList.class)
.set("beanMap", "blabla")
.where().eq("id", bean.getId())
.update();
DB.sqlUpdate("update ebasic_json_list set bean_map=? where id=?")
.setParameters("blabla", bean.getId())
.execute();
try {
// a normal query fails due to invalid JSON content
Ebean.find(EBasicJsonList.class)
DB.find(EBasicJsonList.class)
.setId(bean.getId())
.findOne();
@@ -208,7 +207,7 @@ public class TestDbJson_List extends BaseTestCase {
assertThat(e.getMessage()).contains("beanMap");
}
bean = Ebean.find(EBasicJsonList.class)
bean = DB.find(EBasicJsonList.class)
.setId(bean.getId())
.setAllowLoadErrors() // allow invalid JSON content
.findOne();
@@ -220,6 +219,6 @@ public class TestDbJson_List extends BaseTestCase {
.isInstanceOf(TextException.class)
.hasMessageContaining("blabla");
Ebean.delete(bean);
DB.delete(bean);
}
}
@@ -1,14 +1,16 @@
package org.tests.json;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.text.json.EJson;
import io.ebeantest.LoggedSql;
import org.tests.model.json.EBasicJsonMap;
import org.junit.Test;
import org.tests.model.json.EBasicJsonMapDetail;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@@ -29,9 +31,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.getDetails().add(new EBasicJsonMapDetail("detail1"));
bean.getDetails().add(new EBasicJsonMapDetail("detail2"));
Ebean.save(bean);
DB.save(bean);
Query<EBasicJsonMap> query1 = Ebean.find(EBasicJsonMap.class)
Query<EBasicJsonMap> query1 = DB.find(EBasicJsonMap.class)
.fetch("details")
.where().startsWith("details.name", "detail")
.query();
@@ -40,7 +42,7 @@ public class TestJsonMapBasic extends BaseTestCase {
assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) ");
Query<EBasicJsonMap> query2 = Ebean.find(EBasicJsonMap.class)
Query<EBasicJsonMap> query2 = DB.find(EBasicJsonMap.class)
.where().startsWith("details.name", "detail")
.query();
query2.findList();
@@ -60,9 +62,9 @@ public class TestJsonMapBasic extends BaseTestCase {
bean.setName("one");
bean.setContent(content);
Ebean.save(bean);
DB.save(bean);
EBasicJsonMap bean1 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean1 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals(bean.getId(), bean1.getId());
assertEquals(bean.getName(), bean1.getName());
@@ -70,16 +72,16 @@ public class TestJsonMapBasic extends BaseTestCase {
assertEquals(18L, bean1.getContent().get("docId"));
bean1.setName("just change name");
Ebean.save(bean1);
DB.save(bean1);
// content changes detected - dirty state so included in update
Map<String, Object> content1 = bean1.getContent();
content1.put("additional", "newValue");
content1.put("docId", 99L);
bean1.setName("two");
Ebean.save(bean1);
DB.save(bean1);
EBasicJsonMap bean2 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean2 = DB.find(EBasicJsonMap.class, bean.getId());
// name changed and docId changed
assertEquals("two", bean2.getName());
@@ -89,12 +91,48 @@ public class TestJsonMapBasic extends BaseTestCase {
content1.put("additional", "modValue");
bean1.setName("three");
bean1.setContent(content1);
Ebean.save(bean1);
DB.save(bean1);
EBasicJsonMap bean3 = Ebean.find(EBasicJsonMap.class, bean.getId());
EBasicJsonMap bean3 = DB.find(EBasicJsonMap.class, bean.getId());
assertEquals("three", bean3.getName());
assertEquals(99L, bean3.getContent().get("docId"));
assertEquals("modValue", bean3.getContent().get("additional"));
}
@Test
public void updateQuery_bindingMap() throws IOException {
String s0 = "{\"docId\":22,\"contentId\":\"initialDoc\"}";
Map<String, Object> content = EJson.parseObject(s0);
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("one");
bean.setContent(content);
DB.save(bean);
String s1 = "{\"docId\":222,\"contentId\":\"updatedDoc222\"}";
Map<String, Object> content1 = EJson.parseObject(s1);
LoggedSql.start();
final int rows = DB.update(EBasicJsonMap.class)
.set("content", content1)
.where().eq("id", bean.getId())
.update();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("update ebasic_json_map set content=? where id = ?");
assertThat(rows).isEqualTo(1);
final EBasicJsonMap found = DB.find(EBasicJsonMap.class, bean.getId());
final Map<String, Object> content2 = found.getContent();
assertThat(content2.get("contentId")).isEqualTo("updatedDoc222");
assertThat(content2.get("docId")).isEqualTo(222L);
DB.delete(found);
}
}
@@ -0,0 +1,69 @@
package org.tests.lifecycle;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.tests.model.basic.EBasicLog;
import org.tests.model.basic.EBasicWithLog;
import io.ebean.BaseTestCase;
import io.ebean.DB;
public class TestLifecycleWithLog extends BaseTestCase {
private List<String> getLogs() {
List<String> ret = DB.find(EBasicLog.class)
.select("name")
.findSingleAttributeList();
DB.find(EBasicLog.class).delete();
return ret;
}
@Test
public void testCUD() {
EBasicWithLog bean = new EBasicWithLog();
bean.setId(1L);
bean.setName("Test1");
DB.save(bean);
assertThat(getLogs()).contains("prePersist", "postPersist");
bean.setName("Test2");
DB.save(bean);
assertThat(getLogs()).contains("preUpdate", "postUpdate");
DB.delete(bean);
assertThat(getLogs()).contains("preSoftDelete", "postSoftDelete");
DB.deletePermanent(bean);
assertThat(getLogs()).contains("preRemove", "postRemove");
}
@Test
public void testCUDBatch() {
EBasicWithLog bean = new EBasicWithLog();
bean.setId(2L);
bean.setName("Test2");
List<EBasicWithLog> beans = Arrays.asList(bean);
DB.saveAll(beans);
assertThat(getLogs()).contains("prePersist", "postPersist");
bean.setName("Test2Modified");
DB.saveAll(beans);
assertThat(getLogs()).contains("preUpdate", "postUpdate");
DB.deleteAll(beans);
assertThat(getLogs()).contains("preSoftDelete", "postSoftDelete");
DB.deleteAllPermanent(beans);
assertThat(getLogs()).contains("preRemove", "postRemove");
}
}
@@ -0,0 +1,32 @@
package org.tests.model.basic;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "e_basic_log")
public class EBasicLog {
@Id
Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,124 @@
package org.tests.model.basic;
import io.ebean.DB;
import io.ebean.annotation.PostSoftDelete;
import io.ebean.annotation.PreSoftDelete;
import io.ebean.annotation.SoftDelete;
import javax.annotation.PostConstruct;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name = "e_basic_withlog")
public class EBasicWithLog {
@Id
Long id;
String name;
@SoftDelete
boolean deleted;
@Version
Long version;
@PrePersist
public void prePersist() {
writeLog("prePersist");
}
@PostPersist
public void postPersist() {
writeLog("postPersist");
}
@PreUpdate
public void preUpdate() {
writeLog("preUpdate");
}
@PostUpdate
public void postUpdate() {
writeLog("postUpdate");
}
@PreRemove
public void preRemove() {
writeLog("preRemove");
}
@PostRemove
public void postRemove() {
writeLog("postRemove");
}
@PostSoftDelete
public void postSoftDelete() {
writeLog("postSoftDelete");
}
@PreSoftDelete
public void preSoftDelete() {
writeLog("preSoftDelete");
}
@PostLoad
public void postLoad() {
writeLog("postLoad");
}
@PostConstruct
public void postConstruct() {
writeLog("postConstruct");
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
private void writeLog(String title) {
EBasicLog log = new EBasicLog();
log.setName(title);
DB.save(log);
}
}
@@ -0,0 +1,33 @@
package org.tests.model.cache;
import javax.persistence.Entity;
import javax.persistence.Id;
import io.ebean.annotation.Cache;
@Entity
@Cache(enableQueryCache = true, enableBeanCache = true)
public class M2MCacheChild {
@Id
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,53 @@
package org.tests.model.cache;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import io.ebean.annotation.Cache;
@Entity
@Cache(enableQueryCache = true, enableBeanCache = true)
public class M2MCacheMaster {
@Id
private Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "m2mcache_set1")
private Set<M2MCacheChild> set1 = new LinkedHashSet<>();
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "m2mcache_set2")
private Set<M2MCacheChild> set2 = new LinkedHashSet<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<M2MCacheChild> getSet1() {
return set1;
}
public void setSet1(Set<M2MCacheChild> set1) {
this.set1 = set1;
}
public Set<M2MCacheChild> getSet2() {
return set2;
}
public void setSet2(Set<M2MCacheChild> set2) {
this.set2 = set2;
}
}
@@ -1,7 +1,7 @@
package org.tests.model.history;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
import org.ebeantest.LoggedSqlCollector;
@@ -16,7 +16,7 @@ public class TestHistoryOneToMany extends BaseTestCase {
@IgnorePlatform(Platform.ORACLE)
@Test
public void test() {
public void test() throws InterruptedException {
HiTOne one = new HiTOne("one");
@@ -37,11 +37,12 @@ public class TestHistoryOneToMany extends BaseTestCase {
one.getTwos().add(_22);
Ebean.save(one);
DB.save(one);
Thread.sleep(20);
LoggedSqlCollector.start();
List<HiTOne> list = Ebean.find(HiTOne.class)
List<HiTOne> list = DB.find(HiTOne.class)
.fetch("twos")
.fetch("twos.threes")
.where().ilike("name", "on%")
@@ -51,15 +52,14 @@ public class TestHistoryOneToMany extends BaseTestCase {
List<String> sql = LoggedSqlCollector.stop();
assertThat(list).hasSize(1);
assertThat(list.get(0).getTwos()).hasSize(2);
assertThat(list.get(0).getTwos().get(0).getThrees()).hasSize(3);
if (isH2()) {
assertThat(sql).hasSize(2);
assertSql(sql.get(0)).contains("from hi_tone_with_history t0 where (t0.sys_period_start <= ? and (t0.sys_period_end is null or t0.sys_period_end > ?)) and lower(t0.name) like ? escape'' limit 10");
assertSql(sql.get(1)).contains("from hi_ttwo_with_history t0 left join hi_tthree_with_history t1 on t1.hi_ttwo_id = t0.id and (t1.sys_period_start <= ? and (t1.sys_period_end is null or t1.sys_period_end > ?)) where (t0.sys_period_start <= ? and (t0.sys_period_end is null or t0.sys_period_end > ?)) and (t0.hi_tone_id) in (?)");
}
assertThat(list).hasSize(1);
assertThat(list.get(0).getTwos()).hasSize(2);
assertThat(list.get(0).getTwos().get(0).getThrees()).hasSize(3);
}
}
@@ -15,6 +15,10 @@ public class Address implements IAddress {
private String street;
public Address(String street) {
this.street = street;
}
public long getOid() {
return oid;
}
@@ -0,0 +1,6 @@
package org.tests.model.interfaces;
public interface IPersona {
String persona();
}
@@ -0,0 +1,39 @@
package org.tests.model.interfaces;
import javax.persistence.*;
@Entity
public class Persona implements IPersona {
@Id
private long id;
@Version
private int version;
private final String persona;
@OneToOne(orphanRemoval = true, fetch = FetchType.LAZY, targetEntity = Person.class)
private IPerson person;
public Persona(String persona) {
this.persona = persona;
}
public long getId() {
return id;
}
@Override
public String persona() {
return persona;
}
public void setPerson(IPerson person) {
this.person = person;
}
public IPerson getPerson() {
return person;
}
}
@@ -0,0 +1,40 @@
package org.tests.model.interfaces;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import java.util.List;
@Entity
public class SelfManyMany {
@Id
private long id;
private final String name;
@ManyToMany
// requires explicit @JoinTable
@JoinTable(name = "self_many_bridge",
joinColumns = @JoinColumn(name = "self_1_id"),
inverseJoinColumns = @JoinColumn(name = "self_2_id"))
private List<SelfManyMany> related;
public SelfManyMany(String name) {
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public List<SelfManyMany> getRelated() {
return related;
}
}
@@ -0,0 +1,15 @@
package org.tests.model.interfaces;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import org.junit.Test;
public class TestSelfMany extends BaseTestCase {
@Test
public void self_manyToMany() {
SelfManyMany m = new SelfManyMany("1");
DB.save(m);
}
}
@@ -0,0 +1,38 @@
package org.tests.model.interfaces;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class TestTargetEntity extends BaseTestCase {
@Test
public void test() {
Person person = setup();
Persona persona = new Persona("junk");
persona.setPerson(person);
DB.save(persona);
Persona found = DB.find(Persona.class, persona.getId());
assertThat(found).isNotNull();
assertThat(found.persona()).isEqualTo("junk");
assertThat(found.getPerson().getDefaultAddress().getStreet()).isEqualTo("street");
DB.delete(persona);
DB.delete(person);
DB.delete(person.getDefaultAddress());
}
private Person setup() {
Address address = new Address("street");
DB.save(address);
Person person = new Person();
person.setDefaultAddress(address);
DB.save(person);
return person;
}
}
@@ -0,0 +1,52 @@
package org.tests.model.lazywithcache;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import io.ebean.annotation.Cache;
/**
* Class with @Cache and lazy load property.
*
* @author Noemi Szemenyei, FOCONIS AG
*
*/
@Entity
@Cache(enableQueryCache = true)
public class ChildWithCache {
@Id
Long id;
String name;
@Basic(fetch = FetchType.LAZY)
String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}
@@ -0,0 +1,46 @@
package org.tests.model.lazywithcache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* Parent class with ChildWithCache.
*
*/
@Entity
public class ParentA {
@Id
Long id;
@ManyToOne(optional = true)
ChildWithCache child;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ChildWithCache getChild() {
return child;
}
public void setChild(ChildWithCache child) {
this.child = child;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,36 @@
package org.tests.model.lazywithcache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
/**
* Parent class with ChildWithCache.
*
*/
@Entity
public class ParentB {
@Id
Long id;
@ManyToOne(optional = true)
ChildWithCache child;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ChildWithCache getChild() {
return child;
}
public void setChild(ChildWithCache child) {
this.child = child;
}
}
@@ -0,0 +1,52 @@
package org.tests.model.lazywithcache;
import org.junit.Test;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test with bean cache and lazy loaded property.
*
* @author Noemi Szemenyei, FOCONIS AG
*
*/
public class TestWithCacheAndLazyLoad extends BaseTestCase{
@Test
public void testGetters() {
ChildWithCache child = new ChildWithCache();
child.setId(1L);
child.setName("Child With Cache");
child.setAddress("Address");
DB.save(child);
ParentA parentA = new ParentA();
parentA.setId(1L);
parentA.setName("Parent A");
parentA.setChild(child);
DB.save(parentA);
ParentB parentB = new ParentB();
parentB.setId(1L);
parentB.setChild(child);
DB.save(parentB);
ParentA tempA = DB.find(ParentA.class, 1L);
tempA.getChild().getName(); // load name
ParentB tempB = DB.find(ParentB.class, 1L);
ChildWithCache temp = tempB.getChild();
// if the next line is commented out, the test passes
temp.getName(); // load name from cache --> ebean_intercept.loadedFromCache = true
assertThat(temp.getAddress()).isEqualTo("Address");
assertThat(temp.getName()).isEqualTo("Child With Cache");
}
}
@@ -1,7 +1,7 @@
package org.tests.query;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.DB;
import io.ebean.FutureList;
import io.ebean.Transaction;
import org.tests.model.basic.Order;
@@ -22,17 +22,19 @@ public class TestQueryFindFutureList extends BaseTestCase {
ResetBasicData.reset();
// warm the connection pool
Transaction t0 = Ebean.getServer(null).createTransaction();
Transaction t1 = Ebean.getServer(null).createTransaction();
Transaction t2 = Ebean.getServer(null).createTransaction();
Transaction t0 = DB.createTransaction();
Transaction t1 = DB.createTransaction();
Transaction t2 = DB.createTransaction();
t0.end();
t1.end();
t2.end();
FutureList<Order> futureList = Ebean.find(Order.class).findFutureList();
FutureList<Order> futureList = DB.find(Order.class).findFutureList();
Thread.sleep(10);
futureList.cancel(true);
// calling again is ignored
futureList.cancel(true);
// don't shutdown immediately
Thread.sleep(50);
@@ -43,12 +45,12 @@ public class TestQueryFindFutureList extends BaseTestCase {
ResetBasicData.reset();
FutureList<Order> futureList = Ebean.find(Order.class).findFutureList();
FutureList<Order> futureList = DB.find(Order.class).findFutureList();
// wait for it to complete
List<Order> orders = futureList.getUnchecked();
assertEquals(Ebean.find(Order.class).findCount(), orders.size());
assertEquals(DB.find(Order.class).findCount(), orders.size());
}
@Test
@@ -56,12 +58,12 @@ public class TestQueryFindFutureList extends BaseTestCase {
ResetBasicData.reset();
FutureList<Order> futureList = Ebean.find(Order.class).findFutureList();
FutureList<Order> futureList = DB.find(Order.class).findFutureList();
// wait for it to complete
List<Order> orders = futureList.getUnchecked(1, TimeUnit.SECONDS);
assertEquals(Ebean.find(Order.class).findCount(), orders.size());
assertEquals(DB.find(Order.class).findCount(), orders.size());
}
}
@@ -3,18 +3,24 @@ package org.tests.query.other;
import io.ebean.BaseTestCase;
import io.ebean.CountDistinctOrder;
import io.ebean.CountedValue;
import io.ebean.DB;
import io.ebean.Ebean;
import io.ebean.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.tests.inherit.ChildA;
import org.tests.inherit.Data;
import org.tests.inherit.EUncle;
import org.tests.lazyforeignkeys.MainEntity;
import org.tests.lazyforeignkeys.MainEntityRelation;
import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.tests.model.basic.VwCustomer;
import org.tests.o2m.OmBasicParent;
import java.sql.Date;
import java.time.LocalDate;
@@ -24,6 +30,46 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TestQuerySingleAttribute extends BaseTestCase {
@Test
public void findSingleAttributesTwoToMany() {
ResetBasicData.reset();
// Query without ors with equals causing joins, only one Customer with name Rob exists
Query<Customer> query0 = DB.find(Customer.class)
.select("name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where()
.eq("name", "Rob")
.query();
CountedValue<String> robs0 = (CountedValue<String>) query0.findSingleAttributeList().get(0);
assertThat(robs0.getValue()).isEqualTo("Rob");
assertThat(robs0.getCount()).isEqualTo(1);
// Query with or with equals causing joins
Query<Customer> query = DB.find(Customer.class)
.select("name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where()
.eq("name", "Rob")
.or()
.eq("orders.status", Order.Status.NEW)
.eq("contacts.firstName", "Fred1")
.endOr()
.query();
CountedValue<String> robs = (CountedValue<String>) query.findSingleAttributeList().get(0);
assertThat(robs.getValue()).isEqualTo("Rob");
// only one Customer named rob exists, but 7 is returned for the amount of Customers named Rob
assertThat(robs.getCount()).isEqualTo(1);
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*) " +
"from (select distinct t0.id, t0.name as attribute_ " +
"from o_customer t0 left join contact u1 on u1.customer_id = t0.id left join o_order u2 on u2.kcustomer_id = t0.id " +
"where t0.name = ? and (u2.status = ? or u1.first_name = ?)) r1 " +
"group by r1.attribute_ " +
"order by count(*) desc, r1.attribute_");
}
@Test
public void exampleUsage() {
@@ -102,6 +148,93 @@ public class TestQuerySingleAttribute extends BaseTestCase {
assertThat(name).isNotNull();
}
@Test
public void findSingleAttributeList_with_join_column() {
ResetBasicData.reset();
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "attr1")
.setDistinct(true)
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
List<CountedValue<String>> attr1list = query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select distinct t0.id, t0.id1, t1.attr1 as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1
assertThat(attr1list).isNotNull();
assertThat(attr1list).hasSize(2);
assertThat(attr1list.get(0).getValue()).isEqualTo("a1");
assertThat(attr1list.get(0).getCount()).isEqualTo(2l);
assertThat(attr1list.get(1).getValue()).isEqualTo("a2");
assertThat(attr1list.get(1).getCount()).isEqualTo(1l);
}
@Test
public void findSingleAttributesVariousSelection1() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "attr1")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id1, t1.attr1 as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1
}
@Test
public void findSingleAttributesVariousSelection2() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.select("attr1")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.attr1 as attribute_ from main_entity_relation t0) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_");
}
@Test
public void findSingleAttributesVariousSelection3() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.select("id")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id as attribute_ from main_entity_relation t0) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_");
}
@Test
public void findSingleAttributesVariousSelection4() {
Query<MainEntityRelation> query = Ebean.find(MainEntityRelation.class)
.fetch("entity1", "id")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t0.id1, t1.id as attribute_ from main_entity_relation t0 left join main_entity t1 on t1.id = t0.id1) r1"
+ " group by r1.attribute_"
+ " order by count(*) desc, r1.attribute_"); // sub-query select clause includes t0.id1,
}
@Test
public void findSingleAttributesVariousSelection5() {
Query<OmBasicParent> query = Ebean.find(OmBasicParent.class)
.fetch("children", "name")
.setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
.where().query();
query.findSingleAttributeList();
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*)"
+ " from (select t1.id, t1.name as attribute_ from om_basic_parent t0 left join om_basic_child t1 on t1.parent_id = t0.id) r1 "
+ "group by r1.attribute_ order by count(*) desc, r1.attribute_"); // sub-query select clause includes t1.id,
}
@Test
public void findSingleAttribute_with_aggregate() {
@@ -624,4 +757,43 @@ public class TestQuerySingleAttribute extends BaseTestCase {
System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
}
}
@Before
public void setup() {
MainEntity e1 = new MainEntity();
e1.setId("1");
e1.setAttr1("a1");
DB.save(e1);
MainEntity e2 = new MainEntity();
e2.setId("2");
e2.setAttr1("a2");
DB.save(e2);
MainEntity e3 = new MainEntity();
e3.setId("3");
e3.setAttr1("a1");
DB.save(e3);
MainEntityRelation rel = new MainEntityRelation();
rel.setEntity1(e1);
rel.setEntity2(e1);
DB.save(rel);
rel = new MainEntityRelation();
rel.setEntity1(e2);
rel.setEntity2(e2);
DB.save(rel);
rel = new MainEntityRelation();
rel.setEntity1(e3);
rel.setEntity2(e3);
DB.save(rel);
}
@After
public void cleanup() {
Ebean.find(MainEntityRelation.class).delete();
Ebean.find(MainEntity.class).delete();
}
}
@@ -137,6 +137,27 @@ public class TestSoftDeleteBasic extends BaseTestCase {
query.delete();
}
@Test
public void testFindChild_joinParent() {
EBasicSoftDelete bean = new EBasicSoftDelete();
bean.setName("softDelParent_withChild");
bean.addChild("child1", 10);
DB.save(bean);
Query<EBasicSDChild> query = DB.find(EBasicSDChild.class)
.where()
.eq("owner.name", "softDelParent_withChild")
.query();
List<EBasicSDChild> list = query.findList();
assertSql(query).contains("join ebasic_soft_delete t1 on t1.id = t0.owner_id and t1.deleted =");
assertThat(list).hasSize(1);
// Cleanup created entity
DB.deletePermanent(bean);
}
@Test
public void testFindSoftDeletedList() {
EBasicSoftDelete bean = new EBasicSoftDelete();
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean ddl generation</name>
@@ -29,14 +29,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean external mapping api</name>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -84,7 +84,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean postgis</name>
@@ -24,7 +24,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
@@ -75,7 +75,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -102,7 +102,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<name>ebean querybean</name>
@@ -27,7 +27,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
@@ -67,14 +67,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -101,7 +101,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
@@ -0,0 +1,22 @@
package io.ebean.typequery;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks generated query bean source code.
* <p>
* This is code generated by the query bean generator (annotation processor).
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Generated {
/**
* The name of the generator used to generate this source.
*/
String value();
}
@@ -0,0 +1,35 @@
package org.example.domain;
import org.example.domain.api.ACity;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.List;
@Entity
public class AreaImpl {
@Id
long id;
@OneToMany(targetEntity = CityImpl.class, cascade = CascadeType.ALL)
List<ACity> cities;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<ACity> getCities() {
return cities;
}
public void setCities(List<ACity> cities) {
this.cities = cities;
}
}
@@ -1,8 +1,8 @@
package org.example.domain;
import io.ebean.Model;
import io.ebean.annotation.CreatedTimestamp;
import io.ebean.annotation.UpdatedTimestamp;
import io.ebean.annotation.WhenCreated;
import io.ebean.annotation.WhenModified;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@@ -11,10 +11,10 @@ import java.sql.Timestamp;
/**
* Base domain object with Id, version, whenCreated and whenUpdated.
*
*
* <p>
* Extending Model to enable the 'active record' style.
*
*
* <p>
* whenCreated and whenUpdated are generally useful for maintaining external search services (like
* elasticsearch) and audit.
@@ -28,10 +28,10 @@ public abstract class BaseModel extends Model {
@Version
Long version;
@CreatedTimestamp
@WhenCreated
Timestamp whenCreated;
@UpdatedTimestamp
@WhenModified
Timestamp whenUpdated;
public Long getId() {
@@ -0,0 +1,36 @@
package org.example.domain;
import org.example.domain.api.ACity;
import org.example.domain.api.ACountry;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class CityImpl implements ACity {
@Id
long id;
String name;
@ManyToOne(targetEntity = CountryImpl.class)
ACountry country;
@Override
public long id() {
return id;
}
@Override
public String name() {
return null;
}
@Override
public ACountry country() {
return country;
}
}
@@ -2,13 +2,10 @@ package org.example.domain;
import io.ebean.annotation.DbArray;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Contact entity bean.
@@ -22,28 +19,32 @@ public class Contact extends BaseModel {
@Column(length=50)
String firstName;
@Column(length=50)
String lastName;
@Column(length=200)
String email;
@Column(length=20)
String phone;
@ManyToOne(optional=false)
Customer customer;
@OneToMany(mappedBy = "contact")
List<ContactNote> notes;
@OneToMany(cascade = CascadeType.PERSIST)
@MapKey(name="key")
Map<String,ContactOther> others;
/**
* Default constructor.
*/
public Contact() {
}
/**
* Construct with a firstName and lastName.
*/
@@ -51,7 +52,7 @@ public class Contact extends BaseModel {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
@@ -0,0 +1,32 @@
package org.example.domain;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* Contact entity bean.
*/
@Entity
@Table(name="be_contact_other")
public class ContactOther extends BaseModel {
String key;
int something;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getSomething() {
return something;
}
public void setSomething(int something) {
this.something = something;
}
}
@@ -0,0 +1,18 @@
package org.example.domain;
import org.example.domain.api.ACountry;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class CountryImpl implements ACountry {
@Id
String code;
@Override
public String code() {
return code;
}
}
@@ -0,0 +1,10 @@
package org.example.domain.api;
public interface ACity {
long id();
String name();
ACountry country();
}
@@ -0,0 +1,5 @@
package org.example.domain.api;
public interface ACountry {
String code();
}
@@ -0,0 +1,15 @@
package org.querytest;
import org.example.domain.query.QContact;
import org.junit.Test;
public class QContactTest {
@Test
public void test_oneToManyMap() {
new QContact()
.others.fetch()
.findList();
}
}
@@ -0,0 +1,24 @@
package org.querytest;
import org.example.domain.query.QAreaImpl;
import org.example.domain.query.QCityImpl;
import org.junit.Test;
public class TargetTest {
@Test
public void test_oneToMany() {
new QAreaImpl()
.cities.fetch()
.findList();
}
@Test
public void test_manyToOne() {
new QCityImpl()
.country.fetch()
.findList();
}
}
+7 -7
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -76,7 +76,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
@@ -118,6 +118,6 @@ public class ClusterTest {
}
private void allowAsyncMessaging() throws InterruptedException {
Thread.sleep(10);
Thread.sleep(20);
}
}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<name>ebean test</name>
@@ -43,14 +43,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
@@ -146,7 +146,7 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.18</version>
<version>2.19</version>
<extensions>true</extensions>
<configuration>
<tiles>
@@ -1,22 +1,18 @@
datasource:
db:
username: sa
password:
password: sa
databaseUrl: jdbc:h2:mem:tests
pg:
username: sa
password:
password: sa
databaseUrl: jdbc:h2:mem:tests
ebean:
# migration:
# run: false
#
# ddl:
# generate: true
# run: true
## createOnly: true
ddl:
generate: true
run: true
docstore:
url: http://127.0.0.1:9200
@@ -26,57 +22,9 @@ ebean:
# useDocker: true
elasticVersion: 5.6
# create: true
test:
redis: latest
platform: mariadb #, postgres, mysql, mariadb, oracle, sqlserver, hana
# useDocker: false
# dockerMode: dropCreate
ddlMode: dropCreate # none | dropCreate | create | migrations
dbName: junk
postgres:
version: 9.6
extensions: pgcryto, hstore
username: asd
password: test
url: asd
driver: asd
docker:
postgres:
# port: 6432
version: 9.6
extensions: pgcryto, hstore
username: ${test_db}
password: test
databaseUrl: jdbc:postgresql://localhost:6432/${test_db}
databaseDriver: org.postgresql.Driver
mysql:
version: 5.6
username: ${test_db}
password: test
databaseUrl: jdbc:mysql://localhost:4306/${test_db}
databaseDriver: com.mysql.jdbc.Driver
sqlserver:
version: 2017-CE
username: ${test_db}
password: SqlS3rv#r
databaseUrl: jdbc:sqlserver://localhost:1433;databaseName=${test_db}
databaseDriver: com.microsoft.sqlserver.jdbc.SQLServerDriver
oracle:
username: ${test_db}
password: test
databaseUrl: jdbc:oracle:thin:@127.0.0.1:1521:XE
databaseDriver: oracle.jdbc.driver.OracleDriver
hana:
username: ${test_db}
password: HXEHana1
databaseUrl: jdbc:sap://localhost:39017/?databaseName=HXE
databaseDriver: com.sap.db.jdbc.Driver
@@ -1,21 +0,0 @@
postgres.version=9.6
postgres.dbName=test_db
postgres.dbUser=test_user
postgres.dbPassword=test
postgres.dbExtensions=hstore,pgcrypto
sqlserver.version=2017-CU2
#sqlserver.port=1433
#sqlserver.dbName=test_db
#sqlserver.dbUser=test_user
#sqlserver.dbPassword=SqlS3rv#r
hana.version=2.00.033.00.20180925.2
hana.port=39117
hana.instanceNumber=91
hana.passwordsUrl=file:///hana/mounts/passwords.json
hana.mountsDirectory=/data/dockermounts
# agree to the SAP license (https://www.sap.com/docs/download/cmp/2016/06/sap-hana-express-dev-agmt-and-exhibit.pdf)
hana.agreeToSapLicense=false
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>ebean composite</name>
@@ -22,34 +22,34 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<!-- In future ebean-ddl-generator would only be dependency of ebean-test -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
<!-- In future this is optional and not included by default -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>kotlin querybean generator</name>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -43,7 +43,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -64,7 +64,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<scope>test</scope>
</dependency>
@@ -144,7 +144,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.5.0</version>
<version>12.6.6</version>
<executions>
<execution>
<id>test</id>
@@ -3,11 +3,8 @@ package io.ebean.querybean.generator;
interface Constants {
String AT_GENERATED = "@Generated(\"io.ebean.querybean.kotlin-generator\")";
String AT_TYPEQUERYBEAN = "@TypeQueryBean(\"v1\")";
String GENERATED_9 = "javax.annotation.processing.Generated";
String GENERATED_8 = "javax.annotation.Generated";
String GENERATED = "io.ebean.typequery.Generated";
String MAPPED_SUPERCLASS = "javax.persistence.MappedSuperclass";
String INHERITANCE = "javax.persistence.Inheritance";
@@ -50,7 +50,6 @@ class ProcessingContext implements Constants {
private final Filer filer;
private final Messager messager;
private final Elements elementUtils;
private final String generatedAnnotation;
private final PropertyTypeMap propertyTypeMap = new PropertyTypeMap();
@@ -99,9 +98,6 @@ class ProcessingContext implements Constants {
this.filer = processingEnv.getFiler();
this.messager = processingEnv.getMessager();
this.elementUtils = processingEnv.getElementUtils();
boolean jdk8 = processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_8) <= 0;
this.generatedAnnotation = generatedAnnotation(jdk8);
this.generatedSources = initGeneratedSources(processingEnv);
this.readModuleInfo = new ReadModuleInfo(this);
}
@@ -122,13 +118,6 @@ class ProcessingContext implements Constants {
return elementUtils.getTypeElement(EBEAN_COMPONENT);
}
private String generatedAnnotation(boolean jdk8) {
if (jdk8) {
return isTypeAvailable(GENERATED_8) ? GENERATED_8 : null;
}
return isTypeAvailable(GENERATED_9) ? GENERATED_9 : null;
}
private String initGeneratedSources(ProcessingEnvironment processingEnv) {
String generatedDir = processingEnv.getOptions().get("kapt.kotlin.generated");
return (generatedDir != null) ? generatedDir : "target/generated-sources/kapt/compile";
@@ -303,47 +292,51 @@ class ProcessingContext implements Constants {
return new PropertyTypeEnum(fullType, Split.shortName(fullType));
}
// look for targetEntity annotation attribute
final String targetEntity = readTargetEntity(field);
if (targetEntity != null) {
final TypeElement element = elementUtils.getTypeElement(targetEntity);
if (isEntityOrEmbedded(element)) {
return createPropertyTypeAssoc(typeDef(element.asType()));
}
}
if (isEntityOrEmbedded(fieldType)) {
// public QAssocContact<QCustomer> contacts;
return createPropertyTypeAssoc(typeDef(typeMirror));
}
PropertyType result = null;
if (typeMirror.getKind() == TypeKind.DECLARED) {
DeclaredType declaredType = (DeclaredType) typeMirror;
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() == 1) {
TypeMirror argType = typeArguments.get(0);
if (argType.getKind() == TypeKind.WILDCARD) {
argType = ((WildcardType) argType).getExtendsBound();
}
Element argElement = typeUtils.asElement(argType);
Element argElement = asElement(argType);
if (isEntityOrEmbedded(argElement)) {
result = createPropertyTypeAssoc(typeDef(argElement.asType()));
} else {
// look for targetEntity annotation attribute
final String targetEntity = readTargetEntity(field);
if (targetEntity != null) {
final TypeElement element = elementUtils.getTypeElement(targetEntity);
if (isEntityOrEmbedded(element)) {
result = createPropertyTypeAssoc(typeDef(element.asType()));
}
}
return createPropertyTypeAssoc(typeDef(argElement.asType()));
}
} else if (typeArguments.size() == 2) {
TypeMirror argType = typeArguments.get(1);
Element argElement = asElement(argType);
if (isEntityOrEmbedded(argElement)) {
return createPropertyTypeAssoc(typeDef(argElement.asType()));
}
}
}
if (result != null) {
return result;
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
return new PropertyTypeScalarComparable(typeMirror.toString());
} else {
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
return new PropertyTypeScalarComparable(typeMirror.toString());
} else {
return new PropertyTypeScalar(typeMirror.toString());
}
return new PropertyTypeScalar(typeMirror.toString());
}
}
private Element asElement(TypeMirror argType) {
if (argType.getKind() == TypeKind.WILDCARD) {
argType = ((WildcardType) argType).getExtendsBound();
}
return typeUtils.asElement(argType);
}
private boolean typeInstanceOf(final TypeMirror typeMirror, final CharSequence desiredInterface) {
TypeElement typeElement = (TypeElement) typeUtils.asElement(typeMirror);
if (typeElement == null || typeElement.getQualifiedName().contentEquals("java.lang.Object")) {
@@ -426,14 +419,6 @@ class ProcessingContext implements Constants {
messager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args));
}
boolean isGeneratedAvailable() {
return generatedAnnotation != null;
}
String getGeneratedAnnotation() {
return generatedAnnotation;
}
void readModuleInfo() {
String factory = loadMetaInfServices();
if (factory != null) {
@@ -90,10 +90,7 @@ class SimpleModuleInfoWriter {
writer.append("import java.util.ArrayList;").eol();
writer.append("import java.util.Collections;").eol();
writer.append("import java.util.List;").eol();
final String generated = processingContext.getGeneratedAnnotation();
if (generated != null) {
writer.append("import %s;", generated).eol();
}
writer.append("import %s;", Constants.GENERATED).eol();
writer.eol();
writer.append("import io.ebean.config.ModuleInfo;").eol();
writer.append("import io.ebean.config.ModuleInfoLoader;").eol();
@@ -102,9 +99,7 @@ class SimpleModuleInfoWriter {
}
void buildAtContextModule(Append writer) {
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append("@ModuleInfo(");
if (processingContext.hasOtherClasses()) {
writer.append("other={%s}, ", otherClasses());
@@ -88,11 +88,7 @@ class SimpleQueryBeanWriter {
}
private void gatherPropertyDetails() {
final String generated = processingContext.getGeneratedAnnotation();
if (generated != null) {
importTypes.add(generated);
}
importTypes.add(Constants.GENERATED);
importTypes.add(beanFullName);
importTypes.add(Constants.TQROOTBEAN);
importTypes.add(Constants.TYPEQUERYBEAN);
@@ -282,9 +278,7 @@ class SimpleQueryBeanWriter {
writer.append(" * ").eol();
writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol();
writer.append(" */").eol();
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
lang().beginAssocClass(writer, shortName, origShortName);
@@ -294,9 +288,7 @@ class SimpleQueryBeanWriter {
writer.append(" * ").eol();
writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol();
writer.append(" */").eol();
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
lang().beginClass(writer, shortName);
}
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>12.6.4</version>
<version>12.6.7</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -18,7 +18,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
<tag>ebean-parent-12.6.7</tag>
</scm>
<licenses>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
<version>12.6.7</version>
</parent>
<name>querybean generator</name>
@@ -5,9 +5,7 @@ interface Constants {
String AT_GENERATED = "@Generated(\"io.ebean.querybean.generator\")";
String AT_TYPEQUERYBEAN = "@TypeQueryBean(\"v1\")";
String GENERATED_9 = "javax.annotation.processing.Generated";
String GENERATED_8 = "javax.annotation.Generated";
String GENERATED = "io.ebean.typequery.Generated";
String MAPPED_SUPERCLASS = "javax.persistence.MappedSuperclass";
String INHERITANCE = "javax.persistence.Inheritance";
@@ -35,4 +33,4 @@ interface Constants {
String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf";
String METAINF_SERVICES_MODULELOADER = "META-INF/services/io.ebean.config.ModuleInfoLoader";
}
}
@@ -46,7 +46,6 @@ class ProcessingContext implements Constants {
private final Filer filer;
private final Messager messager;
private final Elements elementUtils;
private final String generatedAnnotation;
private final PropertyTypeMap propertyTypeMap = new PropertyTypeMap();
@@ -95,9 +94,6 @@ class ProcessingContext implements Constants {
this.filer = processingEnv.getFiler();
this.messager = processingEnv.getMessager();
this.elementUtils = processingEnv.getElementUtils();
boolean jdk8 = processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_8) <= 0;
this.generatedAnnotation = generatedAnnotation(jdk8);
this.readModuleInfo = new ReadModuleInfo(this);
}
@@ -117,17 +113,6 @@ class ProcessingContext implements Constants {
return elementUtils.getTypeElement(EBEAN_COMPONENT);
}
private String generatedAnnotation(boolean jdk8) {
if (jdk8) {
return isTypeAvailable(GENERATED_8) ? GENERATED_8 : null;
}
return isTypeAvailable(GENERATED_9) ? GENERATED_9 : null;
}
private boolean isTypeAvailable(String canonicalName) {
return null != elementUtils.getTypeElement(canonicalName);
}
/**
* Gather all the fields (properties) for the given bean element.
*/
@@ -286,6 +271,15 @@ class ProcessingContext implements Constants {
return new PropertyTypeEnum(fullType, Split.shortName(fullType));
}
// look for targetEntity annotation attribute
final String targetEntity = readTargetEntity(field);
if (targetEntity != null) {
final TypeElement element = elementUtils.getTypeElement(targetEntity);
if (isEntityOrEmbedded(element)) {
return createPropertyTypeAssoc(typeDef(element.asType()));
}
}
if (isEntityOrEmbedded(fieldType)) {
// public QAssocContact<QCustomer> contacts;
return createPropertyTypeAssoc(typeDef(typeMirror));
@@ -331,15 +325,11 @@ class ProcessingContext implements Constants {
Element argElement = typeUtils.asElement(typeArguments.get(0));
if (isEntityOrEmbedded(argElement)) {
return createPropertyTypeAssoc(typeDef(argElement.asType()));
} else {
// look for targetEntity annotation attribute
final String targetEntity = readTargetEntity(field);
if (targetEntity != null) {
final TypeElement element = elementUtils.getTypeElement(targetEntity);
if (isEntityOrEmbedded(element)) {
return createPropertyTypeAssoc(typeDef(element.asType()));
}
}
}
} else if (typeArguments.size() == 2) {
Element argElement = typeUtils.asElement(typeArguments.get(1));
if (isEntityOrEmbedded(argElement)) {
return createPropertyTypeAssoc(typeDef(argElement.asType()));
}
}
return null;
@@ -408,14 +398,6 @@ class ProcessingContext implements Constants {
messager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args));
}
boolean isGeneratedAvailable() {
return generatedAnnotation != null;
}
String getGeneratedAnnotation() {
return generatedAnnotation;
}
void readModuleInfo() {
String factory = loadMetaInfServices();
if (factory != null) {
@@ -89,10 +89,7 @@ class SimpleModuleInfoWriter {
writer.append("import java.util.ArrayList;").eol();
writer.append("import java.util.Collections;").eol();
writer.append("import java.util.List;").eol();
final String generated = processingContext.getGeneratedAnnotation();
if (generated != null) {
writer.append("import %s;", generated).eol();
}
writer.append("import %s;", Constants.GENERATED).eol();
writer.eol();
writer.append("import io.ebean.config.ModuleInfo;").eol();
writer.append("import io.ebean.config.ModuleInfoLoader;").eol();
@@ -100,9 +97,7 @@ class SimpleModuleInfoWriter {
}
void buildAtContextModule(Append writer) {
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append("@ModuleInfo(");
if (processingContext.hasOtherClasses()) {
writer.append("other={%s}, ", otherClasses());
@@ -62,10 +62,7 @@ class SimpleQueryBeanWriter {
}
private void gatherPropertyDetails() {
final String generated = processingContext.getGeneratedAnnotation();
if (generated != null) {
importTypes.add(generated);
}
importTypes.add(Constants.GENERATED);
importTypes.add(beanFullName);
importTypes.add(Constants.TQROOTBEAN);
importTypes.add(Constants.TYPEQUERYBEAN);
@@ -301,9 +298,7 @@ class SimpleQueryBeanWriter {
writer.append(" * ").eol();
writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol();
writer.append(" */").eol();
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
writer.append("public class Q%s<R> extends TQAssocBean<%s,R> {", shortName, origShortName).eol();
@@ -313,9 +308,7 @@ class SimpleQueryBeanWriter {
writer.append(" * ").eol();
writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol();
writer.append(" */").eol();
if (processingContext.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
writer.append("public class Q%s extends TQRootBean<%1$s,Q%1$s> {", shortName).eol();
}