diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java
index 3e0085a12..36a4212d5 100644
--- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java
+++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java
@@ -16,6 +16,7 @@ import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
+import io.ebean.plugin.CustomDeployParser;
import io.ebean.util.StringHelper;
import javax.persistence.EnumType;
@@ -389,6 +390,7 @@ public class DatabaseConfig {
private List queryAdapters = new ArrayList<>();
private final List bulkTableEventListeners = new ArrayList<>();
private final List configStartupListeners = new ArrayList<>();
+ private final List customDeployParsers = new ArrayList<>();
/**
* By default inserts are included in the change log.
@@ -2674,6 +2676,17 @@ public class DatabaseConfig {
return configStartupListeners;
}
+ /**
+ * Add a CustomDeployParser.
+ */
+ public void addCustomDeployParser(CustomDeployParser customDeployParser) {
+ customDeployParsers.add(customDeployParser);
+ }
+
+ public List getCustomDeployParsers() {
+ return customDeployParsers;
+ }
+
/**
* Register all the BeanPersistListener instances.
*
diff --git a/ebean-api/src/main/java/io/ebean/plugin/CustomDeployParser.java b/ebean-api/src/main/java/io/ebean/plugin/CustomDeployParser.java
new file mode 100644
index 000000000..4c854f2f1
--- /dev/null
+++ b/ebean-api/src/main/java/io/ebean/plugin/CustomDeployParser.java
@@ -0,0 +1,15 @@
+package io.ebean.plugin;
+
+import io.ebean.config.dbplatform.DatabasePlatform;
+
+/**
+ * Fired after all beans are parsed. You may implement own parsers to handle custom annotations.
+ * (See test case for example)
+ *
+ * @author Roland Praml, FOCONIS AG
+ */
+@FunctionalInterface
+public interface CustomDeployParser {
+
+ void parse(DeployBeanDescriptorMeta descriptor, DatabasePlatform databasePlatform);
+}
diff --git a/ebean-api/src/main/java/io/ebean/plugin/DeployBeanDescriptorMeta.java b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanDescriptorMeta.java
new file mode 100644
index 000000000..a5afba570
--- /dev/null
+++ b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanDescriptorMeta.java
@@ -0,0 +1,37 @@
+package io.ebean.plugin;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * General deployment information. This is used in {@link CustomDeployParser}.
+ *
+ * @author Roland Praml, FOCONIS AG
+ */
+public interface DeployBeanDescriptorMeta {
+
+ /**
+ * Return a collection of all BeanProperty deployment information.
+ */
+ public Collection extends DeployBeanPropertyMeta> propertiesAll();
+
+ /**
+ * Get a BeanProperty by its name.
+ */
+ public DeployBeanPropertyMeta getBeanProperty(String secondaryBeanName);
+
+ /**
+ * Return the DeployBeanDescriptorMeta for the given bean class.
+ */
+ public DeployBeanDescriptorMeta getDeployBeanDescriptorMeta(Class> propertyType);
+
+ /**
+ * Returns the discriminator column, if any.
+ * @return
+ */
+ public String getDiscriminatorColumn();
+
+ public String getBaseTable();
+
+ DeployBeanPropertyMeta idProperty();
+}
diff --git a/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyAssocMeta.java b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyAssocMeta.java
new file mode 100644
index 000000000..d7d1d637a
--- /dev/null
+++ b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyAssocMeta.java
@@ -0,0 +1,23 @@
+package io.ebean.plugin;
+
+public interface DeployBeanPropertyAssocMeta extends DeployBeanPropertyMeta {
+
+ /**
+ * Return the mappedBy deployment attribute.
+ *
+ * This is the name of the property in the 'detail' bean that maps back to
+ * this 'master' bean.
+ *
+ */
+ String getMappedBy();
+
+ /**
+ * Return the base table for this association.
+ *
+ * This has the table name which is used to determine the relationship for
+ * this association.
+ *
+ */
+ String getBaseTable();
+
+}
diff --git a/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyMeta.java b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyMeta.java
new file mode 100644
index 000000000..b581181d2
--- /dev/null
+++ b/ebean-api/src/main/java/io/ebean/plugin/DeployBeanPropertyMeta.java
@@ -0,0 +1,38 @@
+package io.ebean.plugin;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public interface DeployBeanPropertyMeta {
+
+ /**
+ * Return the name of the property.
+ */
+ String getName();
+
+ /**
+ * The database column name this is mapped to.
+ */
+ String getDbColumn();
+
+ /**
+ * Return the bean Field associated with this property.
+ */
+ Field getField();
+
+ /**
+ * The property is based on a formula.
+ */
+ void setSqlFormula(String sqlSelect, String sqlJoin);
+
+ /**
+ * Return the bean type.
+ */
+ Class> getOwningType();
+
+ /**
+ * Return the property type.
+ */
+ Class> getPropertyType();
+
+}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
index 4009c9d49..afff3e2a0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
@@ -168,6 +168,7 @@ public final class DefaultContainer implements SpiContainer {
bootup.addPersistListeners(config.getPersistListeners());
bootup.addQueryAdapters(config.getQueryAdapters());
bootup.addServerConfigStartup(config.getServerConfigStartupListeners());
+ bootup.addCustomDeployParser(config.getCustomDeployParsers());
bootup.addChangeLogInstances(config);
bootup.runServerConfigStartup(config);
return bootup;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/bootup/BootupClasses.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/bootup/BootupClasses.java
index 491739c13..ce34e56d2 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/bootup/BootupClasses.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/bootup/BootupClasses.java
@@ -11,6 +11,7 @@ import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
+import io.ebean.plugin.CustomDeployParser;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.api.CoreLog;
import org.slf4j.Logger;
@@ -51,6 +52,7 @@ public class BootupClasses implements Predicate> {
private final List> beanPersistListenerCandidates = new ArrayList<>();
private final List> beanQueryAdapterCandidates = new ArrayList<>();
private final List> serverConfigStartupCandidates = new ArrayList<>();
+ private final List> customDeployParserCandidates = new ArrayList<>();
private final List idGeneratorInstances = new ArrayList<>();
private final List beanPersistControllerInstances = new ArrayList<>();
@@ -60,6 +62,7 @@ public class BootupClasses implements Predicate> {
private final List beanPersistListenerInstances = new ArrayList<>();
private final List beanQueryAdapterInstances = new ArrayList<>();
private final List serverConfigStartupInstances = new ArrayList<>();
+ private final List customDeployParserInstances = new ArrayList<>();
// single objects
private Class extends ChangeLogPrepare> changeLogPrepareClass;
@@ -169,6 +172,10 @@ public class BootupClasses implements Predicate> {
add(startupInstances, serverConfigStartupInstances, serverConfigStartupCandidates);
}
+ public void addCustomDeployParser(List customDeployParser) {
+ add(customDeployParser, customDeployParserInstances, customDeployParserCandidates);
+ }
+
public void addChangeLogInstances(DatabaseConfig config) {
readAuditPrepare = config.getReadAuditPrepare();
readAuditLogger = config.getReadAuditLogger();
@@ -285,6 +292,10 @@ public class BootupClasses implements Predicate> {
return createAdd(beanQueryAdapterInstances, beanQueryAdapterCandidates);
}
+ public List getCustomDeployParsers() {
+ return createAdd(customDeployParserInstances, customDeployParserCandidates);
+ }
+
/**
* Return the list of Embeddable classes.
*/
@@ -404,6 +415,11 @@ public class BootupClasses implements Predicate> {
interesting = true;
}
+ if (CustomDeployParser.class.isAssignableFrom(cls)) {
+ customDeployParserCandidates.add((Class extends CustomDeployParser>) cls);
+ interesting = true;
+ }
+
// single instances, last assigned wins
if (ChangeLogListener.class.isAssignableFrom(cls)) {
changeLogListenerClass = (Class extends ChangeLogListener>) cls;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
index 3c949b6e1..6a5c66888 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java
@@ -74,6 +74,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
private final BeanFinderManager beanFinderManager;
private final PersistListenerManager persistListenerManager;
private final BeanQueryAdapterManager beanQueryAdapterManager;
+ private final CustomDeployParserManager customDeployParserManager;
private final NamingConvention namingConvention;
private final DeployCreateProperties createProperties;
private final BeanManagerFactory beanManagerFactory;
@@ -154,6 +155,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
this.persistListenerManager = new PersistListenerManager(bootupClasses);
this.beanQueryAdapterManager = new BeanQueryAdapterManager(bootupClasses);
this.beanFinderManager = new BeanFinderManager(bootupClasses);
+ this.customDeployParserManager = new CustomDeployParserManager(bootupClasses);
this.transientProperties = new TransientProperties();
this.changeLogPrepare = config.changeLogPrepare(bootupClasses.getChangeLogPrepare());
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
@@ -301,6 +303,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
readEntityBeanTable();
readEntityDeploymentAssociations();
readInheritedIdGenerators();
+ deployInfoMap.values().forEach(customDeployParserManager::parse);
// creates the BeanDescriptors
readEntityRelationships();
List> list = new ArrayList<>(descMap.values());
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/CustomDeployParserManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/CustomDeployParserManager.java
new file mode 100644
index 000000000..77fd807c4
--- /dev/null
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/CustomDeployParserManager.java
@@ -0,0 +1,23 @@
+package io.ebeaninternal.server.deploy;
+
+import java.util.List;
+
+import io.ebean.plugin.CustomDeployParser;
+import io.ebeaninternal.server.core.bootup.BootupClasses;
+import io.ebeaninternal.server.deploy.parse.DeployBeanInfo;
+
+public class CustomDeployParserManager {
+
+ private final List parsers;
+
+ public CustomDeployParserManager(BootupClasses bootupClasses) {
+ parsers = bootupClasses.getCustomDeployParsers();
+ }
+
+ public void parse(DeployBeanInfo> value) {
+ for (CustomDeployParser parser : parsers) {
+ parser.parse(value.getDescriptor(), value.getUtil().getDbPlatform());
+ }
+ }
+
+}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
index f6282db2d..2b5783aaa 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
@@ -16,6 +16,7 @@ import io.ebean.event.BeanPostConstructListener;
import io.ebean.event.BeanPostLoad;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.event.changelog.ChangeLogFilter;
+import io.ebean.plugin.DeployBeanDescriptorMeta;
import io.ebean.text.PathProperties;
import io.ebean.util.AnnotationUtil;
import io.ebean.util.SplitName;
@@ -55,7 +56,7 @@ import java.util.Set;
/**
* Describes Beans including their deployment information.
*/
-public class DeployBeanDescriptor {
+public class DeployBeanDescriptor implements DeployBeanDescriptorMeta {
private static final Map EMPTY_NAMED_QUERY = new HashMap<>();
@@ -199,7 +200,7 @@ public class DeployBeanDescriptor {
/**
* Return the DeployBeanInfo for the given bean class.
*/
- DeployBeanInfo> getDeploy(Class> cls) {
+ public DeployBeanInfo> getDeploy(Class> cls) {
return manager.deploy(cls);
}
@@ -619,6 +620,7 @@ public class DeployBeanDescriptor {
* Return the base table. Only properties mapped to the base table are by
* default persisted.
*/
+ @Override
public String getBaseTable() {
return baseTable;
}
@@ -696,6 +698,7 @@ public class DeployBeanDescriptor {
/**
* Get a BeanProperty by its name.
*/
+ @Override
public DeployBeanProperty getBeanProperty(String propName) {
return propMap.get(propName);
}
@@ -815,6 +818,7 @@ public class DeployBeanDescriptor {
/**
* Return a collection of all BeanProperty deployment information.
*/
+ @Override
public Collection propertiesAll() {
return propMap.values();
}
@@ -884,6 +888,7 @@ public class DeployBeanDescriptor {
/**
* Return the BeanProperty that is the Id.
*/
+ @Override
public DeployBeanProperty idProperty() {
if (idProperty != null) {
return idProperty;
@@ -1180,4 +1185,14 @@ public class DeployBeanDescriptor {
}
return base;
}
+
+ @Override
+ public String getDiscriminatorColumn() {
+ return inheritInfo == null ? null : inheritInfo.getDiscriminatorColumn();
+ }
+
+ @Override
+ public DeployBeanDescriptorMeta getDeployBeanDescriptorMeta(Class> propertyType) {
+ return getDeploy(propertyType).getDescriptor();
+ }
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java
index 33d1bf266..36c9710ac 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java
@@ -1,11 +1,25 @@
package io.ebeaninternal.server.deploy.meta;
-import io.ebean.annotation.*;
+import io.ebean.annotation.CreatedTimestamp;
+import io.ebean.annotation.DocCode;
+import io.ebean.annotation.DocProperty;
+import io.ebean.annotation.DocSortable;
+import io.ebean.annotation.Formula;
+import io.ebean.annotation.MutationDetection;
+import io.ebean.annotation.Platform;
+import io.ebean.annotation.SoftDelete;
+import io.ebean.annotation.UpdatedTimestamp;
+import io.ebean.annotation.WhenCreated;
+import io.ebean.annotation.WhenModified;
+import io.ebean.annotation.Where;
+import io.ebean.annotation.WhoCreated;
+import io.ebean.annotation.WhoModified;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.core.type.ScalarType;
+import io.ebean.plugin.DeployBeanPropertyMeta;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
@@ -35,7 +49,7 @@ import java.util.Set;
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
*/
-public class DeployBeanProperty {
+public class DeployBeanProperty implements DeployBeanPropertyMeta {
private static final int ID_ORDER = 1000000;
private static final int UNIDIRECTIONAL_ORDER = 100000;
@@ -406,6 +420,7 @@ public class DeployBeanProperty {
this.owningType = owningType;
}
+ @Override
public Class> getOwningType() {
return owningType;
}
@@ -434,6 +449,7 @@ public class DeployBeanProperty {
/**
* Return the name of the property.
*/
+ @Override
public String getName() {
return name;
}
@@ -448,6 +464,7 @@ public class DeployBeanProperty {
/**
* Return the bean Field associated with this property.
*/
+ @Override
public Field getField() {
return field;
}
@@ -551,6 +568,7 @@ public class DeployBeanProperty {
/**
* The property is based on a formula.
*/
+ @Override
public void setSqlFormula(String formulaSelect, String formulaJoin) {
this.sqlFormulaSelect = formulaSelect;
this.sqlFormulaJoin = formulaJoin.isEmpty() ? null : formulaJoin;
@@ -654,6 +672,7 @@ public class DeployBeanProperty {
/**
* The database column name this is mapped to.
*/
+ @Override
public String getDbColumn() {
if (sqlFormulaSelect != null) {
return sqlFormulaSelect;
@@ -847,6 +866,7 @@ public class DeployBeanProperty {
/**
* Return the property type.
*/
+ @Override
public Class> getPropertyType() {
return propertyType;
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
index 3461be3bd..123972cb0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.deploy.meta;
+import io.ebean.plugin.DeployBeanPropertyAssocMeta;
import io.ebeaninternal.server.deploy.BeanCascadeInfo;
import io.ebeaninternal.server.deploy.BeanTable;
import io.ebeaninternal.server.deploy.PropertyForeignKey;
@@ -7,7 +8,7 @@ import io.ebeaninternal.server.deploy.PropertyForeignKey;
/**
* Abstract base for properties mapped to an associated bean, list, set or map.
*/
-public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty {
+public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty implements DeployBeanPropertyAssocMeta {
/**
* The type of the joined bean.
@@ -129,6 +130,7 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty {
* this 'master' bean.
*
*/
+ @Override
public String getMappedBy() {
return mappedBy;
}
@@ -173,4 +175,9 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty {
public void setTargetType(Class> targetType) {
this.targetType = (Class)targetType;
}
+
+ @Override
+ public String getBaseTable() {
+ return getBeanTable().getBaseTable();
+ }
}
diff --git a/ebean-test/src/test/java/org/tests/model/tevent/CustomFormulaAnnotationParser.java b/ebean-test/src/test/java/org/tests/model/tevent/CustomFormulaAnnotationParser.java
new file mode 100644
index 000000000..3f392aed0
--- /dev/null
+++ b/ebean-test/src/test/java/org/tests/model/tevent/CustomFormulaAnnotationParser.java
@@ -0,0 +1,61 @@
+package org.tests.model.tevent;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import io.ebean.annotation.Formula;
+import io.ebean.config.dbplatform.DatabasePlatform;
+import io.ebean.plugin.CustomDeployParser;
+import io.ebean.plugin.DeployBeanDescriptorMeta;
+import io.ebean.plugin.DeployBeanPropertyMeta;
+import io.ebean.util.AnnotationUtil;
+import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
+
+/**
+ * Custom Annotation parser which parses @Count annotation
+ *
+ * @author Roland Praml, FOCONIS AG
+ */
+public class CustomFormulaAnnotationParser implements CustomDeployParser {
+
+ private int counter;
+
+
+ @Target(FIELD)
+ @Retention(RUNTIME)
+ @Formula(select="TODO", join = "TODO") // meta-formula
+ public @interface Count {
+ String value();
+ }
+
+
+
+ @Override
+ public void parse(final DeployBeanDescriptorMeta descriptor, final DatabasePlatform databasePlatform) {
+ for (DeployBeanPropertyMeta prop : descriptor.propertiesAll()) {
+ readField(descriptor, prop);
+ }
+ }
+
+ private void readField(DeployBeanDescriptorMeta descriptor, DeployBeanPropertyMeta prop) {
+ Count countAnnot = AnnotationUtil.get(prop.getField(), Count.class);
+ if (countAnnot != null) {
+ // @Count found, so build the (complex) count formula
+ DeployBeanPropertyAssocMany> countProp = (DeployBeanPropertyAssocMany>) descriptor.getBeanProperty(countAnnot.value());
+ counter++;
+ String tmpTable = "f"+counter;
+ String sqlSelect = "coalesce(" + tmpTable + ".child_count, 0)";
+ String parentId = countProp.getMappedBy() + "_id";
+ String tableName = countProp.getBeanTable().getBaseTable();
+ String sqlJoin = "left join (select " + parentId +", count(*) as child_count from " + tableName + " GROUP BY " + parentId + " )"
+ + " " + tmpTable + " on " + tmpTable + "." +parentId + " = ${ta}." + descriptor.idProperty().getDbColumn();
+ prop.setSqlFormula(sqlSelect, sqlJoin);
+// prop.setSqlFormula("f1.child_count",
+// "join (select parent_id, count(*) as child_count from child_entity GROUP BY parent_id) f1 on f1.parent_id = ${ta}.id");
+ }
+ }
+
+}
diff --git a/ebean-test/src/test/java/org/tests/model/tevent/TEventOne.java b/ebean-test/src/test/java/org/tests/model/tevent/TEventOne.java
index 896d5a147..3107e56a1 100644
--- a/ebean-test/src/test/java/org/tests/model/tevent/TEventOne.java
+++ b/ebean-test/src/test/java/org/tests/model/tevent/TEventOne.java
@@ -41,6 +41,11 @@ public class TEventOne {
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL)
List logs;
+ @CustomFormulaAnnotationParser.Count("logs")
+ //@Formula(select = "f1.child_count",
+ //join = "left join (select event_id, count(*) as child_count from tevent_many GROUP BY event_id ) as f1 on f1.event_id = ${ta}.id")
+ Long customFormula;
+
public TEventOne(String name, Status status) {
this.name = name;
this.status = status;
@@ -63,6 +68,10 @@ public class TEventOne {
return count;
}
+ public Long getCustomFormula() {
+ return customFormula;
+ }
+
public Double getTotalUnits() {
return totalUnits;
}
diff --git a/ebean-test/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/ebean-test/src/test/java/org/tests/query/aggregation/TestAggregationCount.java
index f60686f3d..5efd69bf8 100644
--- a/ebean-test/src/test/java/org/tests/query/aggregation/TestAggregationCount.java
+++ b/ebean-test/src/test/java/org/tests/query/aggregation/TestAggregationCount.java
@@ -48,7 +48,7 @@ public class TestAggregationCount extends BaseTestCase {
List list = query.findList();
String sql = sqlOf(query, 5);
- assertThat(sql).contains("select t0.id, t0.name, t0.status, t0.version, t0.event_id from tevent_one t0");
+ assertThat(sql).contains("select t0.id, t0.name, t0.status, coalesce(f1.child_count, 0), t0.version, t0.event_id from tevent_one t0");
for (TEventOne eventOne : list) {
// lazy loading on Aggregation properties