package jef.database.wrapper.variable; import java.sql.SQLException; import java.util.Collection; import javax.persistence.PersistenceException; import jef.database.Condition; import jef.database.Condition.Operator; import jef.database.DbUtils; import jef.database.Field; import jef.database.IQueryableEntity; import jef.database.VariableConverter; import jef.database.dialect.type.ColumnMapping; import jef.database.meta.FBIField; import jef.database.meta.ITableMetadata; import jef.database.meta.TupleField; import jef.database.query.ConditionQuery; import jef.database.query.JoinElement; import jef.database.query.Query; import jef.tools.Assert; import jef.tools.reflect.BeanWrapper; /* * 描述字段加条件用于匹配绑定变量参数 * 每个实例对应一个SQL中的问号,通过List来确定其在绑定SQL中的序号 */ public class QueryLookupVariable extends Variable { private Field field;// 这个Field可以描述一个实际的条件路径 private Operator oper; // 操作符 private ITableMetadata meta; private static final Object NOT_FOUND = new Object(); private VariableConverter callback; public QueryLookupVariable(Field field, Operator oper, VariableConverter callback) { this(field, oper); this.callback = callback; } public QueryLookupVariable(Field field, Operator oper) { Class<?> clz = field.getClass(); if (clz == TupleField.class) { this.meta = ((TupleField) field).getMeta(); this.field = field; this.oper = oper; return; } Assert.isTrue(clz.isEnum() || clz == FBIField.class, "The Field in bind variable desc must be a metamodel field"); this.field = field; this.oper = oper; this.meta = DbUtils.getTableMeta(field); } public ColumnMapping getColumnType() { return meta == null ? null : meta.getColumnDef(field); } public VariableConverter getCallback() { return callback; } public void setCallback(VariableConverter callback) { this.callback = callback; } public String toString() { return name(); } public Field getField() { return field; } public Operator getOper() { return oper; } public String name() { return field.name().concat(" " + oper.getKey()); } public void setInBatch(boolean b) { } @Override Object jdbcSet(BindVariableContext context, int index, ConditionQuery query) { try { Collection<Condition> conds = null; IQueryableEntity obj = null; if (query != null) { if (query instanceof JoinElement) { conds = ((JoinElement) query).getConditions(); if (query instanceof Query<?>) { obj = ((Query<?>) query).getInstance(); } } } Object value = getWhereVariable(conds, obj); try { value = context.setValueInPsmt(index, value, getColumnType()); } catch (Exception e) { String field = getField().name(); ColumnMapping colType = getColumnType(); throw new SQLException("The query param type error, field=" + field + " type=" + (colType == null ? "" : colType.getClass().getSimpleName()) + "\n" + e.getClass().getName() + ":" + e.getMessage()); } return value; } catch (SQLException ex) { throw new PersistenceException("Error while setting [+field.name()+], error type=" + ex.getClass().getName(), ex); } } /** * 从conditionList或者bean当中获取指定的field的绑定参数值 * * @param conds * 条件列表 * @param bean * 实例 * @param variableDesc * 要获取的具体值的匹配条件标记 * @return */ private Object getWhereVariable(Collection<Condition> conds, IQueryableEntity obj) { Object result = NOT_FOUND; for (Condition c : conds) { if (c.getField() == getField() && c.getOperator() == getOper()) { result = c.getValue(); break; } } if (result == NOT_FOUND && obj != null && getOper() == Operator.EQUALS) { BeanWrapper bean = BeanWrapper.wrap(obj, BeanWrapper.FAST); result = bean.getPropertyValue(getField().name()); } if (result == NOT_FOUND) { // 因为发生了TupleField在批操作过程中发生变化,造成无法定位这一特殊BUG,此处针对这一特定场景进行检测,用来提供更为实用的信息。 for (Condition c : conds) { if (c.getField().name().equals(getField().name()) && c.getOperator() == getOper()) { throw new IllegalArgumentException(this + " has a match condition but belongs to another table metadata." + c.getField() + " <> " + getField()); } } throw new IllegalArgumentException(this + "'s value not found in a batch update query."); } return this.callback == null ? result : callback.process(result); } @Override public Object getConstantValue() { throw new UnsupportedOperationException(); } }