introduce new syntax for aggregate functions applying to collections
max(element x.y), min(index x.y), sum(element x.y) and rationalize the node types here
This commit is contained in:
parent
38fc97feb3
commit
4b5e6e1969
|
@ -1782,7 +1782,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List<Phone> phones = entityManager.createQuery(
|
||||
"select p " +
|
||||
"from Phone p " +
|
||||
"where maxelement(p.calls) = :call",
|
||||
"where max(element p.calls) = :call",
|
||||
Phone.class)
|
||||
.setParameter("call", call)
|
||||
.getResultList();
|
||||
|
@ -1800,7 +1800,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List<Phone> phones = entityManager.createQuery(
|
||||
"select p " +
|
||||
"from Phone p " +
|
||||
"where minelement(p.calls) = :call",
|
||||
"where min(element p.calls) = :call",
|
||||
Phone.class)
|
||||
.setParameter("call", call)
|
||||
.getResultList();
|
||||
|
@ -1817,7 +1817,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List<Person> persons = entityManager.createQuery(
|
||||
"select p " +
|
||||
"from Person p " +
|
||||
"where maxindex(p.phones) = 0",
|
||||
"where max(index p.phones) = 0",
|
||||
Person.class)
|
||||
.getResultList();
|
||||
//end::hql-collection-expressions-example[]
|
||||
|
@ -1991,7 +1991,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List<Person> persons = entityManager.createQuery(
|
||||
"select pr " +
|
||||
"from Person pr " +
|
||||
"where pr.phones[maxindex(pr.phones)].type = 'LAND_LINE'",
|
||||
"where pr.phones[max(index pr.phones)].type = 'LAND_LINE'",
|
||||
Person.class)
|
||||
.getResultList();
|
||||
//end::hql-collection-index-operator-example[]
|
||||
|
|
|
@ -145,6 +145,7 @@ AND : [aA] [nN] [dD];
|
|||
ANY : [aA] [nN] [yY];
|
||||
AS : [aA] [sS];
|
||||
ASC : [aA] [sS] [cC];
|
||||
AVG : [aA] [vV] [gG];
|
||||
BY : [bB] [yY];
|
||||
BETWEEN : [bB] [eE] [tT] [wW] [eE] [eE] [nN];
|
||||
BOTH : [bB] [oO] [tT] [hH];
|
||||
|
@ -164,6 +165,7 @@ DAY : [dD] [aA] [yY];
|
|||
DELETE : [dD] [eE] [lL] [eE] [tT] [eE];
|
||||
DESC : [dD] [eE] [sS] [cC];
|
||||
DISTINCT : [dD] [iI] [sS] [tT] [iI] [nN] [cC] [tT];
|
||||
ELEMENT : [eE] [lL] [eE] [mM] [eE] [nN] [tT];
|
||||
ELEMENTS : [eE] [lL] [eE] [mM] [eE] [nN] [tT] [sS];
|
||||
ELSE : [eE] [lL] [sS] [eE];
|
||||
EMPTY : [eE] [mM] [pP] [tT] [yY];
|
||||
|
@ -208,7 +210,9 @@ LOCAL_DATE : [lL] [oO] [cC] [aA] [lL] '_' [dD] [aA] [tT] [eE];
|
|||
LOCAL_DATETIME : [lL] [oO] [cC] [aA] [lL] '_' [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
|
||||
LOCAL_TIME : [lL] [oO] [cC] [aA] [lL] '_' [tT] [iI] [mM] [eE];
|
||||
MAP : [mM] [aA] [pP];
|
||||
MAX : [mM] [aA] [xX];
|
||||
MAXELEMENT : [mM] [aA] [xX] [eE] [lL] [eE] [mM] [eE] [nN] [tT];
|
||||
MIN : [mM] [iI] [nN];
|
||||
MAXINDEX : [mM] [aA] [xX] [iI] [nN] [dD] [eE] [xX];
|
||||
MEMBER : [mM] [eE] [mM] [bB] [eE] [rR];
|
||||
MICROSECOND : [mM] [iI] [cC] [rR] [oO] [sS] [eE] [cC] [oO] [nN] [dD];
|
||||
|
@ -247,6 +251,7 @@ SET : [sS] [eE] [tT];
|
|||
SIZE : [sS] [iI] [zZ] [eE];
|
||||
SOME : [sS] [oO] [mM] [eE];
|
||||
SUBSTRING : [sS] [uU] [bB] [sS] [tT] [rR] [iI] [nN] [gG];
|
||||
SUM : [sS] [uM] [mM];
|
||||
THEN : [tT] [hH] [eE] [nN];
|
||||
TIES : [tT] [iI] [eE] [sS];
|
||||
TIME : [tT] [iI] [mM] [eE];
|
||||
|
|
|
@ -948,9 +948,10 @@ function
|
|||
: standardFunction
|
||||
| aggregateFunction
|
||||
| jpaCollectionFunction
|
||||
| hqlCollectionFunction
|
||||
| jpaNonstandardFunction
|
||||
| indexAggregateFunction
|
||||
| elementAggregateFunction
|
||||
| collectionFunctionMisuse
|
||||
| jpaNonstandardFunction
|
||||
| genericFunction
|
||||
;
|
||||
|
||||
|
@ -1002,13 +1003,27 @@ jpaCollectionFunction
|
|||
;
|
||||
|
||||
/**
|
||||
* The special collection functions defined by HQL
|
||||
* The special aggregate collection functions defined by HQL
|
||||
*/
|
||||
hqlCollectionFunction
|
||||
: MAXINDEX LEFT_PAREN path RIGHT_PAREN # MaxIndexFunction
|
||||
| MAXELEMENT LEFT_PAREN path RIGHT_PAREN # MaxElementFunction
|
||||
| MININDEX LEFT_PAREN path RIGHT_PAREN # MinIndexFunction
|
||||
| MINELEMENT LEFT_PAREN path RIGHT_PAREN # MinElementFunction
|
||||
indexAggregateFunction
|
||||
: MAXINDEX LEFT_PAREN path RIGHT_PAREN
|
||||
| MININDEX LEFT_PAREN path RIGHT_PAREN
|
||||
| MAX LEFT_PAREN INDEX path RIGHT_PAREN
|
||||
| MIN LEFT_PAREN INDEX path RIGHT_PAREN
|
||||
| SUM LEFT_PAREN INDEX path RIGHT_PAREN
|
||||
| AVG LEFT_PAREN ELEMENT path RIGHT_PAREN
|
||||
;
|
||||
|
||||
/**
|
||||
* The special aggregate collection functions defined by HQL
|
||||
*/
|
||||
elementAggregateFunction
|
||||
: MAXELEMENT LEFT_PAREN path RIGHT_PAREN
|
||||
| MINELEMENT LEFT_PAREN path RIGHT_PAREN
|
||||
| MAX LEFT_PAREN ELEMENT path RIGHT_PAREN
|
||||
| MIN LEFT_PAREN ELEMENT path RIGHT_PAREN
|
||||
| SUM LEFT_PAREN ELEMENT path RIGHT_PAREN
|
||||
| AVG LEFT_PAREN ELEMENT path RIGHT_PAREN
|
||||
;
|
||||
|
||||
/**
|
||||
|
@ -1365,6 +1380,7 @@ identifier
|
|||
| ANY
|
||||
| AS
|
||||
| ASC
|
||||
| AVG
|
||||
| BETWEEN
|
||||
| BOTH
|
||||
| BY
|
||||
|
@ -1429,11 +1445,13 @@ identifier
|
|||
| LOCAL_DATETIME
|
||||
| LOCAL_TIME
|
||||
| MAP
|
||||
| MAX
|
||||
| MAXELEMENT
|
||||
| MAXINDEX
|
||||
| MEMBER
|
||||
| MICROSECOND
|
||||
| MILLISECOND
|
||||
| MIN
|
||||
| MINELEMENT
|
||||
| MININDEX
|
||||
| MINUTE
|
||||
|
@ -1469,6 +1487,7 @@ identifier
|
|||
| SIZE
|
||||
| SOME
|
||||
| SUBSTRING
|
||||
| SUM
|
||||
| THEN
|
||||
| TIES
|
||||
| TIME
|
||||
|
|
|
@ -102,10 +102,8 @@ import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor;
|
||||
|
@ -3969,57 +3967,40 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmMaxElementPath<?> visitMaxElementFunction(HqlParser.MaxElementFunctionContext ctx) {
|
||||
public SqmElementAggregateFunction<?> visitElementAggregateFunction(HqlParser.ElementAggregateFunctionContext ctx) {
|
||||
if ( creationOptions.useStrictJpaCompliance() ) {
|
||||
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
|
||||
}
|
||||
|
||||
return new SqmMaxElementPath<>( consumePluralAttributeReference( (HqlParser.PathContext) ctx.getChild( 2 ) ) );
|
||||
SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
|
||||
if ( !(pluralPath instanceof SqmPluralValuedSimplePath) ) {
|
||||
throw new SemanticException( "Path '" + ctx.path().getText() + "' did not resolve to a many-valued attribute" );
|
||||
}
|
||||
|
||||
String functionName = ctx.getChild(0).getText().substring(0, 3);
|
||||
return new SqmElementAggregateFunction<>( pluralPath, functionName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMinElementPath<?> visitMinElementFunction(HqlParser.MinElementFunctionContext ctx) {
|
||||
public SqmIndexAggregateFunction<?> visitIndexAggregateFunction(HqlParser.IndexAggregateFunctionContext ctx) {
|
||||
if ( creationOptions.useStrictJpaCompliance() ) {
|
||||
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
|
||||
}
|
||||
|
||||
return new SqmMinElementPath<>( consumePluralAttributeReference( (HqlParser.PathContext) ctx.getChild( 2 ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMaxIndexPath<?> visitMaxIndexFunction(HqlParser.MaxIndexFunctionContext ctx) {
|
||||
if ( creationOptions.useStrictJpaCompliance() ) {
|
||||
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
|
||||
final SqmPath<?> pluralPath = consumePluralAttributeReference( ctx.path() );
|
||||
if ( !(pluralPath instanceof SqmPluralValuedSimplePath) ) {
|
||||
throw new SemanticException( "Path '" + ctx.path().getText() + "' did not resolve to a many-valued attribute" );
|
||||
}
|
||||
|
||||
final SqmPath<?> pluralPath = consumePluralAttributeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
|
||||
if ( !isIndexedPluralAttribute( pluralPath ) ) {
|
||||
throw new SemanticException(
|
||||
"maxindex() function can only be applied to path expressions which resolve to an " +
|
||||
"indexed collection (list,map); specified path [" + ctx.getChild( 2 ).getText() +
|
||||
"indexed collection (list,map); specified path [" + ctx.path() +
|
||||
"] resolved to " + pluralPath.getReferencedPathSource()
|
||||
);
|
||||
}
|
||||
|
||||
return new SqmMaxIndexPath<>( pluralPath );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMinIndexPath<?> visitMinIndexFunction(HqlParser.MinIndexFunctionContext ctx) {
|
||||
if ( creationOptions.useStrictJpaCompliance() ) {
|
||||
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
|
||||
}
|
||||
|
||||
final SqmPath<?> pluralPath = consumePluralAttributeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
|
||||
if ( !isIndexedPluralAttribute( pluralPath ) ) {
|
||||
throw new SemanticException(
|
||||
"minindex() function can only be applied to path expressions which resolve to an " +
|
||||
"indexed collection (list,map); specified path [" + ctx.getChild( 2 ).getText() +
|
||||
"] resolved to " + pluralPath.getReferencedPathSource()
|
||||
);
|
||||
}
|
||||
|
||||
return new SqmMinIndexPath<>( pluralPath );
|
||||
String functionName = ctx.getChild(0).getText().substring(0, 3);
|
||||
return new SqmIndexAggregateFunction<>( pluralPath, functionName );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,10 +20,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
|
@ -152,13 +150,9 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path);
|
||||
|
||||
T visitMaxElementPath(SqmMaxElementPath<?> path);
|
||||
T visitElementAggregateFunction(SqmElementAggregateFunction<?> path);
|
||||
|
||||
T visitMinElementPath(SqmMinElementPath<?> path);
|
||||
|
||||
T visitMaxIndexPath(SqmMaxIndexPath<?> path);
|
||||
|
||||
T visitMinIndexPath(SqmMinIndexPath<?> path);
|
||||
T visitIndexAggregateFunction(SqmIndexAggregateFunction<?> path);
|
||||
|
||||
T visitTreatedPath(SqmTreatedPath<?, ?> sqmTreatedPath);
|
||||
|
||||
|
|
|
@ -25,10 +25,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
|
@ -947,22 +945,12 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitMaxElementPath(SqmMaxElementPath binding) {
|
||||
public Object visitElementAggregateFunction(SqmElementAggregateFunction binding) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMinElementPath(SqmMinElementPath path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMaxIndexPath(SqmMaxIndexPath path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMinIndexPath(SqmMinIndexPath path) {
|
||||
public Object visitIndexAggregateFunction(SqmIndexAggregateFunction path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,10 +23,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
|
@ -318,22 +316,12 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitMaxElementPath(SqmMaxElementPath<?> path) {
|
||||
public Object visitElementAggregateFunction(SqmElementAggregateFunction<?> path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMinElementPath(SqmMinElementPath<?> path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMaxIndexPath(SqmMaxIndexPath<?> path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMinIndexPath(SqmMinIndexPath<?> path) {
|
||||
public Object visitIndexAggregateFunction(SqmIndexAggregateFunction<?> path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,10 +168,8 @@ import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmElementAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexAggregateFunction;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
|
@ -3270,24 +3268,29 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMaxElementPath(SqmMaxElementPath<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, false, true );
|
||||
protected Expression createMinOrMaxIndexOrElement(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
String functionName) {
|
||||
boolean isMinOrMax = functionName.equalsIgnoreCase("min")
|
||||
|| functionName.equalsIgnoreCase("max");
|
||||
// Try to create a lateral sub-query join if possible which allows the re-use of the expression
|
||||
if ( isMinOrMax && creationContext.getSessionFactory().getJdbcServices().getDialect().supportsLateral() ) {
|
||||
return createLateralJoinExpression( pluralPartPath, index, functionName );
|
||||
}
|
||||
else {
|
||||
return createCorrelatedAggregateSubQuery( pluralPartPath, index, functionName );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMinElementPath(SqmMinElementPath<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, false, false );
|
||||
public Expression visitElementAggregateFunction(SqmElementAggregateFunction<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, false, path.getFunctionName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMaxIndexPath(SqmMaxIndexPath<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, true, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression visitMinIndexPath(SqmMinIndexPath<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, true, false );
|
||||
public Expression visitIndexAggregateFunction(SqmIndexAggregateFunction<?> path) {
|
||||
return createMinOrMaxIndexOrElement( path, true, path.getFunctionName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3466,23 +3469,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
};
|
||||
}
|
||||
|
||||
protected Expression createMinOrMaxIndexOrElement(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
boolean max) {
|
||||
// Try to create a lateral sub-query join if possible which allows the re-use of the expression
|
||||
if ( creationContext.getSessionFactory().getJdbcServices().getDialect().supportsLateral() ) {
|
||||
return createLateralJoinExpression( pluralPartPath, index, max );
|
||||
}
|
||||
else {
|
||||
return createCorrelatedAggregateSubQuery( pluralPartPath, index, max );
|
||||
}
|
||||
}
|
||||
|
||||
protected Expression createCorrelatedAggregateSubQuery(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
boolean max) {
|
||||
String function) {
|
||||
prepareReusablePath( pluralPartPath.getLhs(), () -> null );
|
||||
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(
|
||||
|
@ -3520,11 +3510,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
registerPluralTableGroupParts( tableGroup );
|
||||
subQuerySpec.getFromClause().addRoot( tableGroup );
|
||||
|
||||
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext
|
||||
.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( max ? "max" : "min" );
|
||||
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor =
|
||||
(AbstractSqmSelfRenderingFunctionDescriptor) creationContext
|
||||
.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.findFunctionDescriptor( function );
|
||||
final CollectionPart collectionPart = index
|
||||
? pluralAttributeMapping.getIndexDescriptor()
|
||||
: pluralAttributeMapping.getElementDescriptor();
|
||||
|
@ -3591,7 +3582,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
protected Expression createLateralJoinExpression(
|
||||
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
|
||||
boolean index,
|
||||
boolean max) {
|
||||
String functionName) {
|
||||
prepareReusablePath( pluralPartPath.getLhs(), () -> null );
|
||||
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(
|
||||
|
@ -3611,7 +3602,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
modelPart = collectionPart;
|
||||
}
|
||||
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
|
||||
final String pathName = ( max ? "max" : "min" ) + ( index ? "_index" : "_element" );
|
||||
final String pathName = functionName + ( index ? "_index" : "_element" );
|
||||
final String identifierVariable = parentTableGroup.getPrimaryTableReference().getIdentificationVariable()
|
||||
+ "_" + pathName;
|
||||
final NavigablePath queryPath = new NavigablePath( parentTableGroup.getNavigablePath(), pathName, identifierVariable );
|
||||
|
@ -3680,7 +3671,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
subQuerySpec.addSortSpecification(
|
||||
new SortSpecification(
|
||||
columnReference,
|
||||
max ? SortOrder.DESCENDING : SortOrder.ASCENDING
|
||||
functionName.equalsIgnoreCase("max")
|
||||
? SortOrder.DESCENDING
|
||||
: SortOrder.ASCENDING
|
||||
)
|
||||
);
|
||||
resultColumnReferences.add(
|
||||
|
|
|
@ -14,16 +14,23 @@ import org.hibernate.query.sqm.SqmPathSource;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmMaxElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public class SqmElementAggregateFunction<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public static final String NAVIGABLE_NAME = "{max-element}";
|
||||
|
||||
public SqmMaxElementPath(SqmPath<?> pluralDomainPath) {
|
||||
private final String functionName;
|
||||
|
||||
public SqmElementAggregateFunction(SqmPath<?> pluralDomainPath, String functionName) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
|
||||
pluralDomainPath,
|
||||
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
|
||||
);
|
||||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,12 +50,12 @@ public class SqmMaxElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
|||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitMaxElementPath( this );
|
||||
return walker.visitElementAggregateFunction( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "maxelement(" );
|
||||
sb.append(functionName).append( "(" );
|
||||
getLhs().appendHqlString( sb );
|
||||
sb.append( ')' );
|
||||
}
|
|
@ -11,24 +11,25 @@ import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
|||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmMaxIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public class SqmIndexAggregateFunction<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public static final String NAVIGABLE_NAME = "{max-index}";
|
||||
|
||||
private final SqmPathSource<T> indexPathSource;
|
||||
private final String functionName;
|
||||
|
||||
public SqmMaxIndexPath(SqmPath<?> pluralDomainPath) {
|
||||
public SqmIndexAggregateFunction(SqmPath<?> pluralDomainPath, String functionName) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
|
||||
pluralDomainPath,
|
||||
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
|
||||
);
|
||||
this.functionName = functionName;
|
||||
|
||||
if ( getPluralAttribute() instanceof ListPersistentAttribute ) {
|
||||
//noinspection unchecked
|
||||
|
@ -43,6 +44,10 @@ public class SqmMaxIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<?> resolvePathPart(
|
||||
String name,
|
||||
|
@ -60,12 +65,12 @@ public class SqmMaxIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
|||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitMaxIndexPath( this );
|
||||
return walker.visitIndexAggregateFunction( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "maxindex(" );
|
||||
sb.append(functionName).append( "(" );
|
||||
getLhs().appendHqlString( sb );
|
||||
sb.append( ')' );
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmMinElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public static final String NAVIGABLE_NAME = "{min-element}";
|
||||
|
||||
public SqmMinElementPath(SqmPath<?> pluralDomainPath) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
|
||||
pluralDomainPath,
|
||||
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<?> resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<T> getReferencedPathSource() {
|
||||
return getPluralAttribute().getElementPathSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitMinElementPath( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "minelement(" );
|
||||
getLhs().appendHqlString( sb );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmMinIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
|
||||
public static final String NAVIGABLE_NAME = "{min-index}";
|
||||
|
||||
private final SqmPathSource<T> indexPathSource;
|
||||
|
||||
public SqmMinIndexPath(SqmPath<?> pluralDomainPath) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
|
||||
pluralDomainPath,
|
||||
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
|
||||
);
|
||||
|
||||
if ( getPluralAttribute() instanceof ListPersistentAttribute ) {
|
||||
//noinspection unchecked
|
||||
this.indexPathSource = (SqmPathSource<T>) getPluralAttribute().getIndexPathSource();
|
||||
}
|
||||
else if ( getPluralAttribute() instanceof MapPersistentAttribute ) {
|
||||
//noinspection unchecked
|
||||
this.indexPathSource = ( (MapPersistentAttribute<?, T, ?>) getPluralAttribute() ).getKeyPathSource();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException( "Plural attribute [" + getPluralAttribute() + "] is not indexed" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<?> resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<T> getReferencedPathSource() {
|
||||
return indexPathSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
return walker.visitMinIndexPath( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( "minindex(" );
|
||||
getLhs().appendHqlString( sb );
|
||||
sb.append( ')' );
|
||||
}
|
||||
|
||||
}
|
|
@ -43,13 +43,13 @@ public class MapIndexFormulaTest {
|
|||
session.createQuery( "from Group g join g.users u where g.name = 'something' and index(u) = 'nada'" )
|
||||
.list();
|
||||
session.createQuery(
|
||||
"from Group g join g.users u where g.name = 'something' and minindex(u) = 'nada'" )
|
||||
"from Group g where g.name = 'something' and minindex(g.users) = 'nada'" )
|
||||
.list();
|
||||
session.createQuery(
|
||||
"from Group g join g.users u where g.name = 'something' and maxindex(u) = 'nada'" )
|
||||
"from Group g where g.name = 'something' and maxindex(g.users) = 'nada'" )
|
||||
.list();
|
||||
session.createQuery(
|
||||
"from Group g join g.users u where g.name = 'something' and maxindex(u) = 'nada' and maxindex(u) = 'nada'" )
|
||||
"from Group g where g.name = 'something' and maxindex(g.users) = 'nada' and maxindex(g.users) = 'nada'" )
|
||||
.list();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class PluralAttributeMappingTests {
|
|||
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
|
||||
final EntityMappingType containerEntityDescriptor = domainModel.getEntityDescriptor( EntityOfLists.class );
|
||||
|
||||
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 7 ) );
|
||||
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 8 ) );
|
||||
|
||||
final AttributeMapping listOfBasics = containerEntityDescriptor.findAttributeMapping( "listOfBasics" );
|
||||
assertThat( listOfBasics, notNullValue() );
|
||||
|
@ -116,7 +116,7 @@ public class PluralAttributeMappingTests {
|
|||
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
|
||||
final EntityMappingType containerEntityDescriptor = domainModel.getEntityDescriptor( EntityOfMaps.class );
|
||||
|
||||
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 16 ) );
|
||||
assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 17 ) );
|
||||
|
||||
final PluralAttributeMapping basicByBasic = (PluralAttributeMapping) containerEntityDescriptor.findAttributeMapping( "basicByBasic" );
|
||||
assertThat( basicByBasic, notNullValue() );
|
||||
|
|
|
@ -67,10 +67,13 @@ public class FunctionTests {
|
|||
|
||||
EntityOfLists eol = new EntityOfLists(1,"");
|
||||
eol.addBasic("hello");
|
||||
eol.addNumber(1.0);
|
||||
eol.addNumber(2.0);
|
||||
em.persist(eol);
|
||||
|
||||
EntityOfMaps eom = new EntityOfMaps(2,"");
|
||||
eom.addBasicByBasic("hello", "world");
|
||||
eom.addNumberByNumber(1,1.0);
|
||||
em.persist(eom);
|
||||
}
|
||||
);
|
||||
|
@ -90,6 +93,45 @@ public class FunctionTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
@RequiresDialect(HSQLDialect.class)
|
||||
@RequiresDialect(DerbyDialect.class)
|
||||
@RequiresDialect(MySQLDialect.class)
|
||||
@RequiresDialect(SybaseDialect.class)
|
||||
@RequiresDialect(MariaDBDialect.class)
|
||||
@RequiresDialect(TiDBDialect.class)
|
||||
// it's failing on the other dialects due to a bug in query translator
|
||||
public void testMaxMinSumIndexElement(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat( session.createQuery("select max(index eol.listOfNumbers) from EntityOfLists eol")
|
||||
.getSingleResult(), is(1) );
|
||||
assertThat( session.createQuery("select max(element eol.listOfNumbers) from EntityOfLists eol")
|
||||
.list().get(0),
|
||||
// .getSingleResult(),
|
||||
is(2.0) );
|
||||
|
||||
assertThat( session.createQuery("select sum(index eol.listOfNumbers) from EntityOfLists eol")
|
||||
.getSingleResult(), is(1) );
|
||||
assertThat( session.createQuery("select sum(element eol.listOfNumbers) from EntityOfLists eol")
|
||||
.list().get(0),
|
||||
// .getSingleResult(),
|
||||
is(3.0) );
|
||||
|
||||
assertThat( session.createQuery("select max(index eom.numberByNumber) from EntityOfMaps eom")
|
||||
.getSingleResult(), is(1) );
|
||||
assertThat( session.createQuery("select max(element eom.numberByNumber) from EntityOfMaps eom")
|
||||
.getSingleResult(), is(1.0) );
|
||||
|
||||
assertThat( session.createQuery("select sum(index eom.numberByNumber) from EntityOfMaps eom")
|
||||
.getSingleResult(), is(1) );
|
||||
assertThat( session.createQuery("select sum(element eom.numberByNumber) from EntityOfMaps eom")
|
||||
.getSingleResult(), is(1.0) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
@RequiresDialect(HSQLDialect.class)
|
||||
|
@ -102,19 +144,11 @@ public class FunctionTests {
|
|||
public void testMaxindexMaxelement(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat( session.createQuery("select maxindex(l) from EntityOfLists eol join eol.listOfBasics l")
|
||||
.getSingleResult(), is(0) );
|
||||
assertThat( session.createQuery("select maxelement(l) from EntityOfLists eol join eol.listOfBasics l")
|
||||
.getSingleResult(), is("hello") );
|
||||
assertThat( session.createQuery("select maxindex(eol.listOfBasics) from EntityOfLists eol")
|
||||
.getSingleResult(), is(0) );
|
||||
assertThat( session.createQuery("select maxelement(eol.listOfBasics) from EntityOfLists eol")
|
||||
.getSingleResult(), is("hello") );
|
||||
|
||||
assertThat( session.createQuery("select maxindex(m) from EntityOfMaps eom join eom.basicByBasic m")
|
||||
.getSingleResult(), is("hello") );
|
||||
assertThat( session.createQuery("select maxelement(m) from EntityOfMaps eom join eom.basicByBasic m")
|
||||
.getSingleResult(), is("world") );
|
||||
assertThat( session.createQuery("select maxindex(eom.basicByBasic) from EntityOfMaps eom")
|
||||
.getSingleResult(), is("hello") );
|
||||
assertThat( session.createQuery("select maxelement(eom.basicByBasic) from EntityOfMaps eom")
|
||||
|
|
|
@ -126,9 +126,9 @@ public class TernaryTest extends BaseCoreFunctionalTestCase {
|
|||
session.beginTransaction();
|
||||
session.createQuery( "from Employee e join e.managerBySite as m where index(m) is not null" )
|
||||
.list();
|
||||
session.createQuery( "from Employee e join e.managerBySite as m where minIndex(m) is not null" )
|
||||
session.createQuery( "from Employee e where minIndex(e.managerBySite) is not null" )
|
||||
.list();
|
||||
session.createQuery( "from Employee e join e.managerBySite as m where maxIndex(m) is not null" )
|
||||
session.createQuery( "from Employee e where maxIndex(e.managerBySite) is not null" )
|
||||
.list();
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
|
|
@ -29,6 +29,7 @@ public class EntityOfLists {
|
|||
private String name;
|
||||
|
||||
private List<String> listOfBasics;
|
||||
private List<Double> listOfNumbers;
|
||||
|
||||
private List<EnumValue> listOfConvertedEnums;
|
||||
private List<EnumValue> listOfEnums;
|
||||
|
@ -78,6 +79,17 @@ public class EntityOfLists {
|
|||
this.listOfBasics = listOfBasics;
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
@OrderColumn(name="num_indx")
|
||||
@CollectionTable(name = "EntityOfLists_numbers")
|
||||
public List<Double> getListOfNumbers() {
|
||||
return listOfNumbers;
|
||||
}
|
||||
|
||||
public void setListOfNumbers(List<Double> listOfNumbers) {
|
||||
this.listOfNumbers = listOfNumbers;
|
||||
}
|
||||
|
||||
public void addBasic(String basic) {
|
||||
if ( listOfBasics == null ) {
|
||||
listOfBasics = new ArrayList<>();
|
||||
|
@ -85,6 +97,13 @@ public class EntityOfLists {
|
|||
listOfBasics.add( basic );
|
||||
}
|
||||
|
||||
public void addNumber(double number) {
|
||||
if ( listOfNumbers == null ) {
|
||||
listOfNumbers = new ArrayList<>();
|
||||
}
|
||||
listOfNumbers.add( number );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// listOfConvertedEnums
|
||||
|
|
|
@ -40,6 +40,7 @@ public class EntityOfMaps {
|
|||
private String name;
|
||||
|
||||
private Map<String, String> basicByBasic;
|
||||
private Map<Integer, Double> numberByNumber;
|
||||
|
||||
private SortedMap<String, String> sortedBasicByBasic;
|
||||
private SortedMap<String, String> sortedBasicByBasicWithComparator;
|
||||
|
@ -109,6 +110,25 @@ public class EntityOfMaps {
|
|||
basicByBasic.put( key, val );
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(name = "EntityOfMaps_number_number1")
|
||||
@MapKeyColumn(name = "number_key")
|
||||
@Column(name = "number_val")
|
||||
public Map<Integer, Double> getNumberByNumber() {
|
||||
return numberByNumber;
|
||||
}
|
||||
|
||||
public void setNumberByNumber(Map<Integer, Double> numberByNumber) {
|
||||
this.numberByNumber = numberByNumber;
|
||||
}
|
||||
|
||||
public void addNumberByNumber(int key, double val) {
|
||||
if ( numberByNumber == null ) {
|
||||
numberByNumber = new HashMap<>();
|
||||
}
|
||||
numberByNumber.put( key, val );
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// sortedBasicByBasic
|
||||
|
||||
|
|
Loading…
Reference in New Issue