package jef.database.query; import java.util.Arrays; import java.util.Collection; import java.util.List; import jef.database.Condition; import jef.database.Condition.Operator; import jef.database.DbUtils; import jef.database.Field; import jef.database.IConditionField; import jef.database.IConditionField.And; import jef.database.IConditionField.Exists; import jef.database.IConditionField.Not; import jef.database.IConditionField.NotExists; import jef.database.IConditionField.Or; import jef.database.IQueryableEntity; import jef.database.PojoWrapper; import jef.database.QueryAlias; import jef.database.VarObject; import jef.database.annotation.JoinType; import jef.database.meta.FBIField; import jef.database.meta.ITableMetadata; import jef.database.meta.JoinKey; import jef.database.meta.JoinPath; import jef.database.meta.MetaHolder; import jef.database.meta.TupleMetadata; import jef.tools.Assert; import jef.tools.StringUtils; /** * Criteria API的工具类。 * * JEF提供的查询方式包括 1. 简单对象查询(提供各种单表的、批的、级联的数据库操作)<br/> * 2、Criteria API(还可以提供基于多表的、Or/Not、Join的、exists/not * exists、Union的、group/having(投影操作)等各种SQL)。<br/> * 基本上能涵盖标准SQL语法可以执行的各种操作<br/> * 3.NamedQuery/NativeQuery。 (可以实现各种DDL,还有数据库专有语法:如Oracle的分析函数、递归(connect * by)等原生的数据库操作<br/> * 4、NativeCall. 提供对于存储过程的操作。<br/> * 5、其他(如简易接口:selectBySql等,不推荐使用)<br/> * * 这个类提供的是各种Criteria API中的操作。<br/> * 可以帮助实现:自定义Join、指定选择列等功能<br/> * * @author Administrator * */ public class QueryBuilder { protected QueryBuilder() { }; /** * 创建一个查询请求,当不赋任何条件的时候,这个查询带有一个默认条件为为 AllRecordsCondition. * * @param clz * 要查询的表 * @return */ @SuppressWarnings("unchecked") public static <T extends IQueryableEntity> Query<T> create(Class<T> clz) { ITableMetadata meta = MetaHolder.getMeta(clz); QueryImpl<T> query = (QueryImpl<T>) meta.newInstance().getQuery(); query.allRecords = true; return query; } /** * 创建查询条件 * * @param clz * @return */ public static <T extends IQueryableEntity> Terms terms(Class<T> clz) { return create(clz).terms(); } /** * 针对动态表模板,创建指定KEY的查询 * * @param clz * @param key * @return */ public static <T extends IQueryableEntity> Query<T> create(Class<T> clz, String key) { T d; try { d = clz.newInstance(); QueryImpl<T> query = new QueryImpl<T>(d, key); query.allRecords = true; return query; } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * 创建一个非NAtive的Query. * * @param clz * @return */ @SuppressWarnings("unchecked") public static Query<PojoWrapper> createForPOJO(Class<?> clz) { ITableMetadata meta = MetaHolder.getMeta(clz); return (Query<PojoWrapper>) create(meta); } /** * 创建一个查询请求,当不赋任何条件的时候,这个查询带有一个默认条件为为 AllRecordsCondition. * * @param clz * 要查询的表的元模型 {@linkplain ITableMetadata 什么是元模型} * @return */ public static Query<?> create(ITableMetadata meta) { IQueryableEntity d = meta.newInstance(); Query<?> query = d.getQuery(); query.setAllRecordsCondition(); return query; } /** * 创建一个查询请求,当不赋任何条件的时候,这个查询带有一个默认条件为为 AllRecordsCondition. * * @param clz * 要查询的表(动态表)的元模型,{@linkplain ITableMetadata 什么是元模型} * @return */ public static Query<VarObject> create(TupleMetadata meta) { IQueryableEntity d = meta.newInstance(); @SuppressWarnings("unchecked") Query<VarObject> query = d.getQuery(); query.setAllRecordsCondition(); return query; } /** * 将传入的SQLExpression作为条件 * * @param sql * @return */ public static Condition sqlExpression(String sql) { return Condition.get(new SqlExpression(sql), Operator.EQUALS, null); } /** * 创建一个Exists条件 * * @param subQuery * @param joinCondition * @return */ public static Condition exists(Query<?> subQuery, Condition... joinCondition) { Exists ex = new Exists(subQuery); for (Condition c : joinCondition) { subQuery.addCondition(c); } return Condition.get(ex, Operator.EQUALS, null); } /** * 创建一个Not Exists条件 * * @param subQuery * @param joinCondition * @return */ public static Condition notExists(Query<?> subQuery, Condition... joinCondition) { NotExists ex = new NotExists(subQuery); for (Condition c : joinCondition) { subQuery.addCondition(c); } return Condition.get(ex, Operator.EQUALS, null); } /** * 产生Or条件 * * @param c * 多个条件 * @return 将传入的多个条件用or连接,形成一个新的条件 */ public static Condition or(Condition... c) { IConditionField or = new Or(c); return Condition.get(or, Operator.EQUALS, null); } /** * 产生And条件 * * @param c * 多个条件 * @return 将传入的多个条件用and连接,形成一个新的条件 */ public static Condition and(Condition... c) { IConditionField or = new And(c); return Condition.get(or, Operator.EQUALS, null); } /** * 产生Not条件 * * @param c * 传入一个条件 * @return 返回c条件相反的条件 */ public static Condition not(Condition c) { IConditionField or = new Not(c); return Condition.get(or, Operator.EQUALS, null); } /** * 产生相等条件 (=) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field = value} 这样的条件 */ public static Condition eq(Field field, Object value) { return Condition.get(field, Operator.EQUALS, value); } /** * 产生不等条件 (<> 或 !=) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field != value} 这样的条件 */ public static Condition ne(Field field, Object value) { return Condition.get(field, Operator.NOT_EQUALS, value); } /** * 产生大于条件 ( >) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field > value} 这样的条件 */ public static Condition gt(Field field, Object value) { return Condition.get(field, Operator.GREAT, value); } /** * 产生大于等于条件 ( >= ) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field >= value} 这样的条件 */ public static Condition ge(Field field, Object value) { return Condition.get(field, Operator.GREAT_EQUALS, value); } /** * 产生小于条件 (<) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field < value} 这样的条件 */ public static Condition lt(Field field, Object value) { return Condition.get(field, Operator.LESS, value); } /** * 产生小于等于条件 ( <= ) * * @param field * 表的字段 (也可以是函数表达式) * @param value * 条件的值,一般传入String,Number,Date等基本数据,也可传入Field对象、 * 或者是SqlExpression等对象。 * @return 表达式为 {@code field <= value} 这样的条件 */ public static Condition le(Field field, Object value) { return Condition.get(field, Operator.LESS_EQUALS, value); } /** * 产生IN条件 (in) * * @param field * 表的字段(也可以是函数表达式) * @param value * 条件的值 数组 * @return 表达式为 {@code field in (value,...)} 这样的条件 */ public static Condition in(Field field, Object[] values) { return Condition.get(field, Operator.IN, values); } /** * 产生IN条件 * * @param field * 表的字段(也可以是函数表达式) * @param value * 条件的值 数组 * @return 表达式为 {@code field in (value,...)} 这样的条件 */ public static Condition in(Field field, int[] values) { return Condition.get(field, Operator.IN, values); } /** * 产生IN条件 * * @param field * 表的字段(也可以是函数表达式) * @param value * 条件的值 数组 * @return @return 表达式为 {@code field in (value,...)} 这样的条件 */ public static Condition in(Field field, long[] values) { return Condition.get(field, Operator.IN, values); } /** * 产生IN条件 * * @param field * 表的字段(也可以是函数表达式) * @param value * 条件的值 集合 * @return @return 表达式为 {@code field in (value,...)} 这样的条件 */ public static Condition in(Field field, Collection<?> values) { return Condition.get(field, Operator.IN, values); } /** * 产生is null条件 * * @param field * 表的字段(也可以是函数表达式) * @return 表达式为 {@code field is null} 这样的条件 */ public static Condition isNull(Field field) { return Condition.get(field, Operator.IS_NULL, null); } /** * 产生 is not null条件 * * @param field * 表的字段(也可以是函数表达式) * @return 表达式为 {@code field is not null} 这样的条件 */ public static Condition notNull(Field field) { return Condition.get(field, Operator.IS_NOT_NULL, null); } /** * 产生not in条件 * * @param field * 表的字段(也可以是函数表达式) * @param values * not in的条件值 * @return 表达式为 {@code field is not in (value,...)} 这样的条件 */ public static Condition notin(Field field, Object[] values) { return Condition.get(field, Operator.NOT_IN, values); } /** * 产生between条件 * * @param field * 表的字段(也可以是函数表达式) * @param begin * 比较值的下限 * @param end * 比较值的上限 * @return 产生形如 {@code field between begin and end} 这样的条件 */ public static <T extends Comparable<T>> Condition between(Field field, T begin, T end) { return Condition.get(field, Operator.BETWEEN_L_L, new Object[] { begin, end }); } /** * 产生MatchEnd条件, * * @param field * 表的字段(也可以是函数表达式) * @param str * 要匹配的字符串 * @return 产生形如 {@code field like '%str' } 这样的条件,str中原来的的'%' '_'符号会被转义 */ public static Condition matchEnd(Field field, String str) { return Condition.get(field, Operator.MATCH_END, str); } /** * 产生MatchStart条件 * * @param field * 表的字段(也可以是函数表达式) * @param str * 要匹配的字符串 * @return 产生形如 {@code field like 'str%' } 这样的条件,str中原来的的'%' '_'符号会被转义 */ public static Condition matchStart(Field field, String str) { return Condition.get(field, Operator.MATCH_START, str); } /** * 得到一个Like %str%的条件 * * @param field * field 表的字段(也可以是函数表达式) * @param str * 要匹配的字符串 * @return 产生形如 {@code field like '%str%' } 这样的条件,str中原来的的'%' '_'符号会被转义 */ public static Condition matchAny(Field field, String str) { return Condition.get(field, Operator.MATCH_ANY, str); } /** * 得到一个Like条件,参数为自定义的字符串。 例如 * <p> * {@code like(field, "%123_456%")} * <p> * 相当于 * <p> * {@code WHERE field LIKE '%123_456%' } * <p> * * <h3>注意</h3> 这个方法可以自由定义复杂的匹配模板外,但是和matchxxx系列的方法相比,不会对字符串中的'%' * '_'做转义。因此实际使用不当会有SQL注入风险。 * <p> * * @param field * field 表的字段(也可以是函数表达式) * @param str * 要匹配的字符串 * @return 产生形如 {@code field like 'str' } 这样的条件,str中原来的的'%' '_'符号会被保留 */ public static Condition like(Field field, String str) { return Condition.get(field, Operator.MATCH_ANY, new SqlExpression(str)); } /** * 将多个普通查询拼为union查询, 要求每个查询返回的字段个数和字段类型必须一致 * * @param queries * 多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> union(TypedQuery<T>... queries) { Assert.isTrue(queries.length > 0); UnionQuery<T> q = new UnionQuery<T>(Arrays.<ConditionQuery> asList(queries), queries[0].getMeta()); q.setAll(false); return q; } /** * 将多个普通查询拼为union查询。 要求每个查询返回的字段个数和字段类型必须一致 * * @param clz * UNION返回结果的类型 * @param queries * queries 多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> union(Class<T> clz, ConditionQuery... queries) { Assert.isTrue(queries.length > 0); UnionQuery<T> q = new UnionQuery<T>(Arrays.<ConditionQuery> asList(queries), clz); q.setAll(false); return q; } /** * 将多个普通查询拼为union查询 * * @param queries * 构成union的多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> union(ITableMetadata clz, ConditionQuery... queries) { UnionQuery<T> q = new UnionQuery<T>(Arrays.asList(queries), clz); q.setAll(false); return q; } /** * 将多个普通查询拼为union all查询, 要求每个查询返回的字段个数和字段类型必须一致 * * @param queries * 多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> unionAll(TypedQuery<T>... queries) { Assert.isTrue(queries.length > 0); UnionQuery<T> q = new UnionQuery<T>(Arrays.<ConditionQuery> asList(queries), queries[0].getMeta()); return q; } /** * 将多个普通查询拼为union all查询 并指定返回类型 * * @param clz * union all查询要返回的类型 * @param queries * 构成union all的多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> unionAll(Class<T> clz, ConditionQuery... queries) { UnionQuery<T> q = new UnionQuery<T>(Arrays.asList(queries), clz); return q; } /** * 将多个普通查询拼为union all查询 * * @param clz * union all查询要返回的类型 * @param queries * 构成union all的多个查询 * @return UnionQuery对象。 */ public static <T> UnionQuery<T> unionAll(ITableMetadata clz, ConditionQuery... queries) { UnionQuery<T> q = new UnionQuery<T>(Arrays.asList(queries), clz); return q; } /** * 创建内连接 * * @param left * 连接左边的查询。可以是{@link Query}或者{@link Join}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @see #on(Field, Field) * @see #on(Field, Number) * @see #on(Field, String) * @see #on(Field, Operator, Object) * @see #on(Query, Field, Query, Field) */ public static Join innerJoin(JoinElement left, Query<?> right, JoinKey... keys) { JoinPath path = null; if (keys.length > 0) { path = new JoinPath(JoinType.INNER, keys); } Join join = JoinUtil.create(left, right, path, JoinType.INNER, false); if (join == null) join = JoinUtil.create(left, right, path, JoinType.INNER, true); Assert.notNull(join, "Join create failure on !"); return join; } /** * 创建内连接 * * @param left * 连接左边的查询。可以是{@link Query}或者{@link Join}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @see #on(Field, Field) * @see #on(Field, Number) * @see #on(Field, String) * @see #on(Field, Operator, Object) * @see #on(Query, Field, Query, Field) * @deprecated see https://github.com/GeeQuery/ef-orm/issues/46 */ public static Join innerJoinWithRef(Query<?> left, Query<?> right, JoinKey... keys) { JoinElement jl = DbUtils.toReferenceJoinQuery(left, null); return innerJoin(jl, right, keys); } /** * 创建左外连接 * * @param left * 连接左边的查询。可以是{@link Query}或者{@link Join}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @see #on(Field, Field) * @see #on(Field, Number) * @see #on(Field, String) * @see #on(Field, Operator, Object) * @see #on(Query, Field, Query, Field) */ public static Join leftJoin(JoinElement left, Query<?> right, JoinKey... keys) { JoinPath path = null; if (keys.length > 0) { path = new JoinPath(JoinType.LEFT, keys); } Join join = JoinUtil.create(left, right, path, JoinType.LEFT, false); if (join == null) join = JoinUtil.create(left, right, path, JoinType.LEFT, true); Assert.notNull(join, "Join create failure on !"); return join; } /** * 创建右外连接 * * @param left * 连接左边的查询。可以是{@link Query}或者{@link Join}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @see #on(Field, Field) * @see #on(Field, Number) * @see #on(Field, String) * @see #on(Field, Operator, Object) * @see #on(Query, Field, Query, Field) */ public static Join rightJoin(JoinElement left, Query<?> right, JoinKey... keys) { JoinPath path = null; if (keys.length > 0) { path = new JoinPath(JoinType.RIGHT, keys); } Join join = JoinUtil.create(left, right, path, JoinType.RIGHT, false); if (join == null) join = JoinUtil.create(left, right, path, JoinType.RIGHT, true); Assert.notNull(join, "Join create failure on !"); return join; } /** * 创建全外连接 * * @param left * 连接左边的查询。可以是{@link Query}或者{@link Join}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @see #on(Field, Field) * @see #on(Field, Number) * @see #on(Field, String) * @see #on(Field, Operator, Object) * @see #on(Query, Field, Query, Field) */ public static Join outerJoin(JoinElement left, Query<?> right, JoinKey... keys) { JoinPath path = null; if (keys.length > 0) { path = new JoinPath(JoinType.RIGHT, keys); } Join join = JoinUtil.create(left, right, path, JoinType.RIGHT, false); if (join == null) join = JoinUtil.create(left, right, path, JoinType.RIGHT, true); Assert.notNull(join, "Join create failure on !"); return join; } /** * 保留left查询中一对一关系或者多对一关系产生的外连接查询,然后再关联右侧查询对象(左外连接)。 <h3>使用举例</h3> TODO * documented. * * @param left * 连接左边的查询。是{@link Query}对象 * @param right * 右边的查询 * @param keys * 连接路径,可省略。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @deprecated see https://github.com/GeeQuery/ef-orm/issues/46 */ public static Join leftJoinWithRef(Query<?> left, Query<?> right, JoinKey... keys) { JoinElement jl = DbUtils.toReferenceJoinQuery(left, null); return leftJoin(jl, right, keys); } /** * 保留left查询中一对一关系或者多对一关系产生的外连接查询,然后再关联右侧查询对象(右外连接)。 <h3>使用举例</h3> TODO * documented. * * @param left * 连接左边的查询。是{@link Query}对象 * @param right * 右边的查询 * @param keys * 连接路径。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @deprecated see https://github.com/GeeQuery/ef-orm/issues/46 */ public static Join rightJoinWithRef(Query<?> left, Query<?> right, JoinKey... keys) { JoinElement jl = DbUtils.toReferenceJoinQuery(left, null); return rightJoin(jl, right, keys); } /** * 保留left查询中一对一关系或者多对一关系产生的外连接查询,然后再关联右侧查询对象(全外连接)。 <h3>使用举例</h3> TODO * documented. * * @param left * 连接左边的查询。是{@link Query}对象 * @param right * 右边的查询 * @param keys * 连接路径。一般在编程中QB.on()方法来构造 * @return Join查询对象 * @deprecated see https://github.com/GeeQuery/ef-orm/issues/46 */ public static Join outerJoinWithRef(Query<?> left, Query<?> right, JoinKey... keys) { JoinElement jl = DbUtils.toReferenceJoinQuery(left, null); return outerJoin(jl, right, keys); } /** * 创建一个列选择操作器(SelectItems),SelectItems提供了若干方法用于指定select语句中的选择列,包括distinct, * group by, hvaing等语法支持。 使用此API可以构造出投影操作,如max() min() sum()等分组函数。 * * @param query * 查询 * @return 列选择操作器 * @see Selects */ public static Selects selectFrom(JoinElement query) { // if(query instanceof Query<?>){//如果是非连接,检查是否有自动的 // query=DbUtils.toReferenceJoinQuery((Query<?>)query); // } if (query.getSelectItems() != null && (query.getSelectItems() instanceof Selects)) return (Selects) query.getSelectItems(); List<QueryAlias> qs; if (query instanceof Join) { qs = query.prepare().queries; } else { Query<?> q = (Query<?>) query; QueryAlias qa = new QueryAlias("t", q); qs = Arrays.asList(qa); } SelectsImpl select = new SelectsImpl(qs); query.setSelectItems(select); return select; } /** * 清除自定义的选择列,恢复到默认状态 * * @param query * 请求 */ public static void clearCustomSelection(JoinElement query) { query.setSelectItems(null); } /** * 创建一个连接键 <h3>使用举例</h3> * * <pre> * <code> * Query<Department> q1=QB.create(Department.class); //产生一个查询(部门表) * Query<Person> q2=QB.create(Person.class); //产生另一个查询(人员表) * Join join = QB.innerJoin(q1, q2, QB.on(Department.Field.id, Person.Field.deptId)); //人员表关联部门表,按人员表中的deptId字段关联部门表的id字段。 * session.select() * </code> * </pre> * * @param left * 左边的字段 * @param right * 右边的字段 * @return 连接键 * @see #innerJoin(JoinElement, Query, JoinKey...) * @see #leftJoin(JoinElement, Query, JoinKey...) * @see #rightJoin(JoinElement, Query, JoinKey...) * @see #outerJoin(JoinElement, Query, JoinKey...) */ public static JoinKey on(Field left, Field right) { return new JoinKey(left, right); } /** * 创建一个连接键 <h3>使用举例</h3> * * @param left * 左边的字段 * @param right * 等于的值 * @return 生成一个形如 {@code on field = value}这样的SQL字句。 * @see #innerJoin(JoinElement, Query, JoinKey...) * @see #leftJoin(JoinElement, Query, JoinKey...) * @see #rightJoin(JoinElement, Query, JoinKey...) * @see #outerJoin(JoinElement, Query, JoinKey...) */ public static JoinKey on(Field left, Number value) { return new JoinKey(left, new FBIField(String.valueOf(value))); } /** * 创建一个连接键(用于复杂的连接描述,右侧可以是各种常量) * * @param field * @param oper * @param value * @return 连接键 */ public static JoinKey on(Field field, Operator oper, Object value) { return new JoinKey(field, oper, value); } /** * 创建连接键描述 * * @param left * 左边的字段 * @param value * 常量string,即要求等于右侧的常量值 * @return */ public static JoinKey on(Field left, String value) { value = value.replace("'", "''"); String expression = StringUtils.concat("'", value, "'"); return new JoinKey(left, new FBIField(expression)); } /** * 指定所属Query的方式来使用,当同一张表字表关联的时候需要使用。 * * @param left * @param right * @return */ public static JoinKey on(Query<?> t1, Field left, Query<?> t2, Field right) { return new JoinKey(new RefField(t1, left), new RefField(t2, right)); } /** * 描述一个特定Query对象中的Field,但是此时尚不指定该Query对象,要到查询指定时,自动匹配对应的Query对象。 * 此时,要求该Field所使用的表在Join查询中只出现一次。 * * @param field * field * @return */ public static Field fieldOf(Field field) { return new RefField(field); } /** * 描述一个特定Query对象中的Field * * @param q * 特定Query对象 * @param field * field * @return */ public static Field fieldOf(Query<?> q, Field field) { return new RefField(q, field); } /** * 描述一个特定Query对象中的Field * * @param q * 特定Query对象 * @param field * field名称 * @return */ public static Field fieldOf(Query<?> q, String field) { return new RefField(q, field); } /** * 用于在对象的更新字段表中产生一个自增(或自减)的更新描述 <h3>示例</h3> * {@code QB.fieldAdd(foo,Foo.Field.age, 100);} * <p> * 将会形成如下的SQL语句<br /> * <code> * update foo set age = age + ? (实际执行时为 age = age + 100) * </code> * * @param entity * 要更新的对象 * @param field * 需要自增的字段 * @param i * 自增值 */ public static void fieldAdd(IQueryableEntity entity, Field field, int i) { entity.prepareUpdate(field, new JpqlExpression(field.name() + " + :amount_")); entity.getQuery().setAttribute("amount_", i); } /** * 用于在对象的更新字段表中产生一个自增(或自减)的更新描述 <h3>示例</h3> * {@code QB.fieldAdd(foo,Foo.Field.age, 100);} * <p> * 将会形成如下的SQL语句<br /> * <code> * update foo set age = age + ? (实际执行时为 age = age + 100) * </code> * * @param entity * 要更新的对象 * @param field * 需要自增的字段 * @param i * 自增值 */ public static void fieldAdd(IQueryableEntity entity, Field field, double i) { entity.prepareUpdate(field, new JpqlExpression(field.name() + " + :amount_")); entity.getQuery().setAttribute("amount_", i); } }