From 05eb0bfc55bca7cb0028869ceea2cd6853b9201b Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Fri, 15 Jul 2016 23:15:18 +1200 Subject: [PATCH] #777 - ENH: Add support for @NamedQuery and @NamedQueries --- .../server/core/DefaultServer.java | 5 ++- .../server/deploy/BeanDescriptor.java | 14 ++++++-- .../deploy/meta/DeployBeanDescriptor.java | 21 +++++++++++ .../server/deploy/parse/AnnotationClass.java | 14 ++++++++ .../com/avaje/ebean/EbeanServer_eqlTest.java | 36 +++++++++++++++++++ .../inheritance/model/CalculationResult.java | 9 ----- .../com/avaje/tests/model/basic/Customer.java | 9 +++++ 7 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 56c88112b..5bc59014d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -894,6 +894,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { if (desc == null) { throw new PersistenceException(beanType.getName() + " is NOT an Entity Bean registered with this server?"); } + String named = desc.getNamedQuery(namedQuery); + if (named != null) { + return createQuery(beanType, named); + } RawSql rawSql = desc.getNamedRawSql(namedQuery); if (rawSql != null) { DefaultOrmQuery query = createQuery(beanType); @@ -905,7 +909,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { @Override public Query createQuery(Class beanType, String eql) { - DefaultOrmQuery query = createQuery(beanType); EqlParser.parse(eql, query); return query; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 7a7790ccc..c4d51888d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -7,7 +7,6 @@ import com.avaje.ebean.RawSql; import com.avaje.ebean.SqlUpdate; import com.avaje.ebean.Transaction; import com.avaje.ebean.ValuePair; -import com.avaje.ebeaninternal.api.ConcurrencyMode; import com.avaje.ebean.annotation.DocStoreMode; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.EntityBean; @@ -16,8 +15,8 @@ import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebean.bean.PersistenceContextUtil; import com.avaje.ebean.config.EncryptKey; import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebean.config.dbplatform.PlatformIdGenerator; import com.avaje.ebean.config.dbplatform.IdType; +import com.avaje.ebean.config.dbplatform.PlatformIdGenerator; import com.avaje.ebean.event.BeanFindController; import com.avaje.ebean.event.BeanPersistController; import com.avaje.ebean.event.BeanPersistListener; @@ -36,6 +35,7 @@ import com.avaje.ebean.plugin.BeanType; import com.avaje.ebean.plugin.ExpressionPath; import com.avaje.ebean.plugin.Property; import com.avaje.ebeaninternal.api.CQueryPlanKey; +import com.avaje.ebeaninternal.api.ConcurrencyMode; import com.avaje.ebeaninternal.api.LoadContext; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.api.SpiQuery; @@ -111,6 +111,8 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { private final Map namedRawSql; + private final Map namedQuery; + public void merge(EntityBean bean, EntityBean existing) { EntityBeanIntercept fromEbi = bean._ebean_getIntercept(); @@ -414,6 +416,7 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { this.rootBeanType = PersistenceContextUtil.root(beanType); this.prototypeEntityBean = createPrototypeEntityBean(beanType); + this.namedQuery = deploy.getNamedQuery(); this.namedRawSql = deploy.getNamedRawSql(); this.inheritInfo = deploy.getInheritInfo(); @@ -988,6 +991,13 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { return this; } + /** + * Return the named ORM query. + */ + public String getNamedQuery(String name) { + return namedQuery.get(name); + } + /** * Return the named RawSql query. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index fdcba6adb..f3a7768e3 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -46,6 +46,8 @@ import java.util.Map; */ public class DeployBeanDescriptor { + private static final Map EMPTY_NAMED_QUERY = new HashMap(); + private static final Map EMPTY_RAW_MAP = new HashMap(); private static class PropOrder implements Comparator { @@ -73,6 +75,8 @@ public class DeployBeanDescriptor { private Map namedRawSql; + private Map namedQuery; + private EntityType entityType; private DeployBeanPropertyAssocOne unidirectional; @@ -1055,6 +1059,23 @@ public class DeployBeanDescriptor { return serverConfig.getDocStoreConfig().getPersist(); } + /** + * Return the named ORM queries. + */ + public Map getNamedQuery() { + return (namedQuery != null) ? namedQuery : EMPTY_NAMED_QUERY; + } + + /** + * Add a named query. + */ + public void addNamedQuery(String name, String query) { + if (namedQuery == null) { + namedQuery = new LinkedHashMap(); + } + namedQuery.put(name, query); + } + /** * Return the named RawSql queries. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java index d1d6a1354..509133d3d 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java @@ -21,6 +21,8 @@ import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Embeddable; import javax.persistence.Entity; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @@ -177,6 +179,18 @@ public class AnnotationClass extends AnnotationParser { if (cache != null && !disableL2Cache) { descriptor.setCache(cache); } + + NamedQueries namedQueries = cls.getAnnotation(NamedQueries.class); + if (namedQueries != null) { + for (NamedQuery namedQuery : namedQueries.value()) { + descriptor.addNamedQuery(namedQuery.name(), namedQuery.query()); + } + } + + NamedQuery namedQuery = cls.getAnnotation(NamedQuery.class); + if (namedQuery != null) { + descriptor.addNamedQuery(namedQuery.name(), namedQuery.query()); + } } } diff --git a/src/test/java/com/avaje/ebean/EbeanServer_eqlTest.java b/src/test/java/com/avaje/ebean/EbeanServer_eqlTest.java index c3479e470..4361bb2a2 100644 --- a/src/test/java/com/avaje/ebean/EbeanServer_eqlTest.java +++ b/src/test/java/com/avaje/ebean/EbeanServer_eqlTest.java @@ -68,4 +68,40 @@ public class EbeanServer_eqlTest extends BaseTestCase { query.findUnique(); } + @Test + public void namedQuery() { + + ResetBasicData.reset(); + + Query name = server().createNamedQuery(Customer.class, "name"); + name.findList(); + + assertThat(name.getGeneratedSql()).contains("select t0.id c0, t0.name c1 from o_customer t0 order by t0.name"); + } + + @Test + public void namedQuery_withStatus() { + + ResetBasicData.reset(); + + Query name = server().createNamedQuery(Customer.class, "withStatus"); + name.order().clear().asc("status"); + name.findList(); + + assertThat(name.getGeneratedSql()).contains("select t0.id c0, t0.name c1, t0.status c2 from o_customer t0 order by t0.status"); + } + + @Test + public void namedQuery_withContacts() { + + ResetBasicData.reset(); + + Query query = server() + .createNamedQuery(Customer.class, "withContacts") + .setParameter("id", 1); + + query.findUnique(); + + assertThat(query.getGeneratedSql()).contains("from o_customer t0 left outer join contact t1 on t1.customer_id = t0.id "); + } } \ No newline at end of file diff --git a/src/test/java/com/avaje/tests/inheritance/model/CalculationResult.java b/src/test/java/com/avaje/tests/inheritance/model/CalculationResult.java index ec9b8cf9a..76830e0c8 100644 --- a/src/test/java/com/avaje/tests/inheritance/model/CalculationResult.java +++ b/src/test/java/com/avaje/tests/inheritance/model/CalculationResult.java @@ -5,17 +5,8 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; @Entity -@NamedQueries({ - @NamedQuery(name="loadResult", - query="find CalculationResult " + - "fetch productConfiguration "+ - "fetch groupConfiguration "+ - "where charge = :charge") -}) public class CalculationResult { @Id diff --git a/src/test/java/com/avaje/tests/model/basic/Customer.java b/src/test/java/com/avaje/tests/model/basic/Customer.java index 966f1682c..5a4732498 100644 --- a/src/test/java/com/avaje/tests/model/basic/Customer.java +++ b/src/test/java/com/avaje/tests/model/basic/Customer.java @@ -14,6 +14,8 @@ import com.avaje.tests.model.basic.finder.CustomerFinder; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; @@ -27,6 +29,13 @@ import java.util.concurrent.locks.ReentrantLock; /** * Customer entity bean. */ +@NamedQueries( + value = { + @NamedQuery(name = "name", query = "select(name) order by name"), + @NamedQuery(name = "withStatus", query = "select(name,status) order by name") + } +) +@NamedQuery(name="withContacts", query = "fetch contacts (firstName, lastName) where id = :id") @Cache(enableQueryCache = true) @DocStore @ChangeLog(inserts = ChangeLogInsertMode.EXCLUDE, updatesThatInclude = {"name", "status"})