mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e59e72983 | ||
|
|
b56d68dac7 | ||
|
|
213562fcf1 | ||
|
|
d3a09b93c0 | ||
|
|
536ea57369 | ||
|
|
ac1dd4cbab | ||
|
|
bc33e05906 | ||
|
|
8ecc407cb0 | ||
|
|
2672dff512 | ||
|
|
74d907bbce | ||
|
|
53aacabce7 | ||
|
|
ab9cdd8f5b | ||
|
|
b3d439ed11 | ||
|
|
d57657c209 | ||
|
|
dd080c5933 | ||
|
|
0be98d7989 | ||
|
|
fca54dbbe3 | ||
|
|
7ec5fe6a85 | ||
|
|
9ea5505214 | ||
|
|
75d3b566a7 | ||
|
|
e38059f52c | ||
|
|
72331aa945 | ||
|
|
e497c54f82 | ||
|
|
b44091ff3a | ||
|
|
2ab889f889 | ||
|
|
23541e661e | ||
|
|
6778e37652 | ||
|
|
5eac31283d | ||
|
|
38016773d4 | ||
|
|
ad80eb267f | ||
|
|
449e0832e0 | ||
|
|
f28f5c9a01 | ||
|
|
9dd28d8879 | ||
|
|
b47eec99a5 | ||
|
|
99bb55efa0 | ||
|
|
4408eb618a | ||
|
|
9ccd1b1b27 | ||
|
|
0c1657fef5 | ||
|
|
ee393c6485 | ||
|
|
7f68b9d846 | ||
|
|
2035a3344e | ||
|
|
ade36582a0 | ||
|
|
a4b8be61e3 | ||
|
|
b7feb62ecd | ||
|
|
7e48f7c8eb | ||
|
|
501f8111fe | ||
|
|
d8f4503d98 | ||
|
|
0d83978c58 | ||
|
|
69e56be459 | ||
|
|
35a721039d |
+1
-1
@@ -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,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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
+1
-42
@@ -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.
|
||||
*/
|
||||
|
||||
+5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
-13
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
+10
-32
@@ -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());
|
||||
|
||||
+8
-24
@@ -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));
|
||||
}
|
||||
|
||||
-8
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+14
-11
@@ -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;
|
||||
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
+1
-4
@@ -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";
|
||||
|
||||
+26
-41
@@ -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) {
|
||||
|
||||
+2
-7
@@ -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());
|
||||
|
||||
+3
-11
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+14
-32
@@ -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) {
|
||||
|
||||
+2
-7
@@ -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());
|
||||
|
||||
+3
-10
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user