mirror of https://github.com/apache/openjpa.git
OPENJPA-805 JPQL iteration 1 - add support for COALESCE and NULLIF expressions
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@725881 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
cabd344397
commit
debe82b8d0
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.jdbc.kernel.exps;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Joins;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Raw;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Result;
|
||||||
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Select;
|
||||||
|
import org.apache.openjpa.kernel.Filters;
|
||||||
|
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
|
||||||
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coalesce expression.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
public class CoalesceExpression
|
||||||
|
extends AbstractVal {
|
||||||
|
|
||||||
|
private final Val[] _vals;
|
||||||
|
private ClassMetaData _meta = null;
|
||||||
|
private Class _cast = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public CoalesceExpression(Val[] vals) {
|
||||||
|
_vals = vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Val[] getVal() {
|
||||||
|
return _vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
if (_cast != null)
|
||||||
|
return _cast;
|
||||||
|
Class type = _vals[0].getType();
|
||||||
|
for (int i = 1; i < _vals.length; i++)
|
||||||
|
type = Filters.promote(type, _vals[i].getType());
|
||||||
|
if (type == Raw.class)
|
||||||
|
return String.class;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
|
||||||
|
ExpState[] states = new ExpState[_vals.length];
|
||||||
|
Joins joins = null;
|
||||||
|
for (int i = 0; i < _vals.length; i++) {
|
||||||
|
states[i] = _vals[i].initialize(sel, ctx, flags);
|
||||||
|
if (joins == null)
|
||||||
|
joins = states[i].joins;
|
||||||
|
else
|
||||||
|
joins = sel.and(joins, states[i].joins);
|
||||||
|
}
|
||||||
|
return new CoalesceExpState(joins, states);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CoalesceExpState
|
||||||
|
extends ExpState {
|
||||||
|
|
||||||
|
public ExpState[] states;
|
||||||
|
|
||||||
|
public CoalesceExpState(Joins joins, ExpState[] states) {
|
||||||
|
super(joins);
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer buf, int index) {
|
||||||
|
CoalesceExpState cstate = (CoalesceExpState) state;
|
||||||
|
|
||||||
|
buf.append(" COALESCE ");
|
||||||
|
buf.append("(");
|
||||||
|
|
||||||
|
for (int i = 0; i < _vals.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
buf.append(",");
|
||||||
|
_vals[i].appendTo(sel, ctx, cstate.states[i], buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void selectColumns(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
boolean pks) {
|
||||||
|
CoalesceExpState cstate = (CoalesceExpState) state;
|
||||||
|
|
||||||
|
for (int i = 0; i < _vals.length; i++)
|
||||||
|
_vals[i].selectColumns(sel, ctx, cstate.states[i], pks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptVisit(ExpressionVisitor visitor) {
|
||||||
|
visitor.enter(this);
|
||||||
|
for (int i = 0; i < _vals.length; i++)
|
||||||
|
_vals[i].acceptVisit(visitor);
|
||||||
|
visitor.exit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return Val.COALESCE_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
Val other, ExpState otherState) {
|
||||||
|
CoalesceExpState cstate = (CoalesceExpState) state;
|
||||||
|
for (int i = 0; i < _vals.length; i++)
|
||||||
|
_vals[i].calculateValue(sel, ctx, cstate.states[i], null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void groupBy(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
sel.groupBy(newSQLBuffer(sel, ctx, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
calculateValue(sel, ctx, state, null, null);
|
||||||
|
SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
|
||||||
|
appendTo(sel, ctx, state, buf, 0);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object load(ExpContext ctx, ExpState state, Result res)
|
||||||
|
throws SQLException {
|
||||||
|
return Filters.convert(res.getObject(this,
|
||||||
|
JavaSQLTypes.JDBC_DEFAULT, null), getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void orderBy(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
boolean asc) {
|
||||||
|
sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void select(Select sel, ExpContext ctx, ExpState state, boolean pks){
|
||||||
|
sel.select(newSQLBuffer(sel, ctx, state), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMetaData getMetaData() {
|
||||||
|
return _meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplicitType(Class type) {
|
||||||
|
_cast = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetaData(ClassMetaData meta) {
|
||||||
|
_meta = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -447,4 +447,37 @@ public class JDBCExpressionFactory
|
||||||
}
|
}
|
||||||
return new WhenScalar((Val) val1, (Val) val2);
|
return new WhenScalar((Val) val1, (Val) val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value coalesceExpression(Value[] vals) {;
|
||||||
|
Object[] values = new Val[vals.length];
|
||||||
|
for (int i = 0; i < vals.length; i++) {
|
||||||
|
if (vals[i] instanceof Lit) {
|
||||||
|
Lit val = (Lit) vals[i];
|
||||||
|
StringBuffer value = new StringBuffer(val.getValue().toString());
|
||||||
|
if (val.getParseType() == Literal.TYPE_SQ_STRING)
|
||||||
|
value.insert(0, "'").append("'");
|
||||||
|
val.setValue(new Raw(value.toString()));
|
||||||
|
}
|
||||||
|
values[i] = vals[i];
|
||||||
|
}
|
||||||
|
return new CoalesceExpression((Val[]) values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value nullIfExpression(Value val1, Value val2) {
|
||||||
|
if (val1 instanceof Lit) {
|
||||||
|
Lit val = (Lit) val1;
|
||||||
|
StringBuffer value = new StringBuffer(val.getValue().toString());
|
||||||
|
if (val.getParseType() == Literal.TYPE_SQ_STRING)
|
||||||
|
value.insert(0, "'").append("'");
|
||||||
|
val.setValue(new Raw(value.toString()));
|
||||||
|
}
|
||||||
|
if (val2 instanceof Lit) {
|
||||||
|
Lit val = (Lit) val2;
|
||||||
|
StringBuffer value = new StringBuffer(val.getValue().toString());
|
||||||
|
if (val.getParseType() == Literal.TYPE_SQ_STRING)
|
||||||
|
value.insert(0, "'").append("'");
|
||||||
|
val.setValue(new Raw(value.toString()));
|
||||||
|
}
|
||||||
|
return new NullIfExpression((Val) val1, (Val) val2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.jdbc.kernel.exps;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Raw;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Result;
|
||||||
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Select;
|
||||||
|
import org.apache.openjpa.kernel.Filters;
|
||||||
|
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
|
||||||
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NullIf expression.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
public class NullIfExpression
|
||||||
|
extends AbstractVal {
|
||||||
|
|
||||||
|
private final Val _val1;
|
||||||
|
private final Val _val2;
|
||||||
|
private ClassMetaData _meta = null;
|
||||||
|
private Class _cast = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
public NullIfExpression(Val val1, Val val2) {
|
||||||
|
_val1 = val1;
|
||||||
|
_val2 = val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Val getVal1() {
|
||||||
|
return _val1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Val getVal2() {
|
||||||
|
return _val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
if (_cast != null)
|
||||||
|
return _cast;
|
||||||
|
Class c1 = _val1.getType();
|
||||||
|
Class c2 = _val2.getType();
|
||||||
|
Class type = Filters.promote(c1, c2);
|
||||||
|
if (type == Raw.class)
|
||||||
|
return String.class;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
|
||||||
|
ExpState s1 = _val1.initialize(sel, ctx, 0);
|
||||||
|
ExpState s2 = _val2.initialize(sel, ctx, 0);
|
||||||
|
return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer buf, int index) {
|
||||||
|
BinaryOpExpState bstate = (BinaryOpExpState) state;
|
||||||
|
|
||||||
|
buf.append(" NULLIF ");
|
||||||
|
buf.append("(");
|
||||||
|
|
||||||
|
_val1.appendTo(sel, ctx, bstate.state1, buf, 0);
|
||||||
|
buf.append(",");
|
||||||
|
_val2.appendTo(sel, ctx, bstate.state2, buf, 0);
|
||||||
|
|
||||||
|
buf.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void selectColumns(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
boolean pks) {
|
||||||
|
BinaryOpExpState bstate = (BinaryOpExpState) state;
|
||||||
|
_val1.selectColumns(sel, ctx, bstate.state1, true);
|
||||||
|
_val2.selectColumns(sel, ctx, bstate.state2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptVisit(ExpressionVisitor visitor) {
|
||||||
|
visitor.enter(this);
|
||||||
|
_val1.acceptVisit(visitor);
|
||||||
|
_val2.acceptVisit(visitor);
|
||||||
|
visitor.exit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return Val.NULLIF_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
Val other, ExpState otherState) {
|
||||||
|
BinaryOpExpState bstate = (BinaryOpExpState) state;
|
||||||
|
_val1.calculateValue(sel, ctx, bstate.state1, _val2, bstate.state2);
|
||||||
|
_val2.calculateValue(sel, ctx, bstate.state2, _val1, bstate.state1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void groupBy(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
sel.groupBy(newSQLBuffer(sel, ctx, state));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
|
||||||
|
calculateValue(sel, ctx, state, null, null);
|
||||||
|
SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
|
||||||
|
appendTo(sel, ctx, state, buf, 0);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object load(ExpContext ctx, ExpState state, Result res)
|
||||||
|
throws SQLException {
|
||||||
|
return Filters.convert(res.getObject(this,
|
||||||
|
JavaSQLTypes.JDBC_DEFAULT, null), getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void orderBy(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
boolean asc) {
|
||||||
|
sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void select(Select sel, ExpContext ctx, ExpState state, boolean pks){
|
||||||
|
sel.select(newSQLBuffer(sel, ctx, state), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMetaData getMetaData() {
|
||||||
|
return _meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplicitType(Class type) {
|
||||||
|
_cast = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetaData(ClassMetaData meta) {
|
||||||
|
_meta = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ public interface Val
|
||||||
public final int GENERALCASE_VAL = 14;
|
public final int GENERALCASE_VAL = 14;
|
||||||
public final int WHENCONDITION_VAL = 15;
|
public final int WHENCONDITION_VAL = 15;
|
||||||
public final int WHENSCALAR_VAL = 16;
|
public final int WHENSCALAR_VAL = 16;
|
||||||
|
public final int COALESCE_VAL = 17;
|
||||||
|
public final int NULLIF_VAL = 18;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the value. This method should recursively initialize any
|
* Initialize the value. This method should recursively initialize any
|
||||||
|
|
|
@ -428,4 +428,14 @@ public interface ExpressionFactory {
|
||||||
* Return a when scalar_expression clause
|
* Return a when scalar_expression clause
|
||||||
*/
|
*/
|
||||||
public Expression whenScalar(Value val1, Value val2);
|
public Expression whenScalar(Value val1, Value val2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a coalesce expression
|
||||||
|
*/
|
||||||
|
public Value coalesceExpression(Value[] val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a nullif expression
|
||||||
|
*/
|
||||||
|
public Value nullIfExpression(Value val1, Value val2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -745,4 +745,14 @@ public class InMemoryExpressionFactory
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value coalesceExpression(Value[] val) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value nullIfExpression(Value val1, Value val2) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -766,6 +766,12 @@ public class JPQLExpressionBuilder
|
||||||
case JJTWHENSCALAR:
|
case JJTWHENSCALAR:
|
||||||
return getWhenScalar(node);
|
return getWhenScalar(node);
|
||||||
|
|
||||||
|
case JJTCOALESCE:
|
||||||
|
return getCoalesceExpression(node);
|
||||||
|
|
||||||
|
case JJTNULLIF:
|
||||||
|
return getNullIfExpression(node);
|
||||||
|
|
||||||
case JJTWHERE: // top-level WHERE clause
|
case JJTWHERE: // top-level WHERE clause
|
||||||
return getExpression(onlyChild(node));
|
return getExpression(onlyChild(node));
|
||||||
|
|
||||||
|
@ -1502,6 +1508,23 @@ public class JPQLExpressionBuilder
|
||||||
return factory.whenScalar((Value) val1, (Value) val2);
|
return factory.whenScalar((Value) val1, (Value) val2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Value getCoalesceExpression(JPQLNode node) {
|
||||||
|
int nChild = node.getChildCount();
|
||||||
|
|
||||||
|
Object vals[] = new Value[nChild];
|
||||||
|
for (int i = 0; i < nChild; i++)
|
||||||
|
vals[i] = eval(node.children[i]);
|
||||||
|
|
||||||
|
return factory.coalesceExpression((Value[]) vals);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Value getNullIfExpression(JPQLNode node) {
|
||||||
|
Object val1 = eval(firstChild(node));
|
||||||
|
Object val2 = eval(secondChild(node));
|
||||||
|
|
||||||
|
return factory.nullIfExpression((Value) val1, (Value) val2);
|
||||||
|
}
|
||||||
|
|
||||||
private Value getValue(JPQLNode node) {
|
private Value getValue(JPQLNode node) {
|
||||||
return getValue(node, VAR_PATH);
|
return getValue(node, VAR_PATH);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,40 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCoalesceExpressions() {
|
||||||
|
EntityManager em = currentEntityManager();
|
||||||
|
startTx(em);
|
||||||
|
|
||||||
|
|
||||||
|
String query = "SELECT e.name, " +
|
||||||
|
"COALESCE (e.address.country, 'Unknown')" +
|
||||||
|
" FROM CompUser e";
|
||||||
|
List rs = em.createQuery(query).getResultList();
|
||||||
|
Object[] result = (Object[]) rs.get(rs.size()-1);
|
||||||
|
assertEquals("the name is not shade", "Shade", result[0]);
|
||||||
|
assertEquals("Unknown", result[1]);
|
||||||
|
|
||||||
|
endTx(em);
|
||||||
|
endEm(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNullIfExpressions() {
|
||||||
|
EntityManager em = currentEntityManager();
|
||||||
|
startTx(em);
|
||||||
|
|
||||||
|
String query = "SELECT e.name, " +
|
||||||
|
"NULLIF (e.address.country, 'USA')" +
|
||||||
|
" FROM CompUser e";
|
||||||
|
|
||||||
|
List rs = em.createQuery(query).getResultList();
|
||||||
|
Object[] result = (Object[]) rs.get(1);
|
||||||
|
assertEquals("the name is not shannon ", "Shannon ", result[0]);
|
||||||
|
assertNull("is not null", result[1]);
|
||||||
|
|
||||||
|
endTx(em);
|
||||||
|
endEm(em);
|
||||||
|
}
|
||||||
|
|
||||||
public void testSimpleCaseExpressions() {
|
public void testSimpleCaseExpressions() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue