package jef.database;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import jef.common.log.LogUtil;
import jef.database.annotation.JoinDescription;
import jef.database.dialect.type.ColumnMapping;
import jef.database.jsqlparser.statement.select.OrderBy;
import jef.database.jsqlparser.statement.select.OrderByElement;
import jef.database.meta.AbstractRefField;
import jef.database.meta.ISelectProvider;
import jef.database.meta.ITableMetadata;
import jef.database.meta.JoinPath;
import jef.database.meta.Reference;
import jef.database.meta.ReferenceField;
import jef.database.query.JoinElement;
import jef.database.query.OrderField;
import jef.database.query.Query;
import jef.database.query.QueryBuilder;
import jef.tools.StringUtils;
import jef.tools.reflect.BeanWrapper;
final class CascadeLoaderTask implements LazyLoadTask {
private ReverseReferenceProcessor reverse;
private Query<?> query;
private JoinElement finalQuery;
private QueryOption option;
private JoinPath joinPath;
private Map<Reference, List<Condition>> filters;
private List<Condition> currentFilter;
private ITableMetadata targetTableMeta;
private List<AbstractRefField> refs;
private List<OrderField> orders;
private String keyOfJoinTable;
/**
*
* @param entry
* 模型中的静态条件
* @param filters
* 人工的动态过滤条件
*/
public CascadeLoaderTask(Map.Entry<Reference, List<AbstractRefField>> entry, Map<Reference, List<Condition>> filters) {
this.filters = filters;
this.refs = entry.getValue(); // 要装填的字段
Reference ref = entry.getKey(); // 引用关系
this.currentFilter=filters.get(ref);
joinPath = ref.toJoinPath();
if (joinPath == null) {
LogUtil.error("No join key found: " + ref);
}
this.reverse = CascadeUtil.getReverseProcessor(ref);
if(joinPath.getRelationTable()!=null) {
query = QueryBuilder.create(joinPath.getRelationTable());
keyOfJoinTable=ref.getThisType().getName().replace('.', '_')+"_OBJ";
}else {
query = QueryBuilder.create(ref.getTargetType());
}
targetTableMeta = query.getMeta();
// 将预制的两个条件加入
if (joinPath.getDescription() != null) {
JoinDescription desc = joinPath.getDescription();
if (desc.maxRows() > 0) {
query.setMaxResult(desc.maxRows());
}
}
if (StringUtils.isNotEmpty(joinPath.getOrderBy())) {
orders = new ArrayList<OrderField>();
OrderBy order = DbUtils.parseOrderBy(joinPath.getOrderBy());
for (OrderByElement ele : order.getOrderByElements()) {
ColumnMapping field = targetTableMeta.findField(ele.getExpression().toString());
if (field != null) {
orders.add(new OrderField(field.field(), ele.isAsc()));
}
}
}
// 计算查询目标的引用关系
finalQuery = query;
option = QueryOption.createFrom(query);
if(reverse!=null)
option.skipReference=reverse.refs;
if (!targetTableMeta.getRefFieldsByName().isEmpty()) {
finalQuery = DbUtils.toReferenceJoinQuery(query, reverse == null ? null : reverse.refs); // 去除引用关系后将其转为Join,用这种方式进行的查询不查询反向的多对1关系
}
}
public void process(Session db, Object obj) throws SQLException {
if(!db.isOpen()){
throw new SQLException("try to load field "+refs.get(0).getName()+" but the session was already closed!");
}
LogUtil.debug("processing Cascadeload [{}]",this.refs.get(0).getReference());
BeanWrapper bean = BeanWrapper.wrap(obj);
if (DbUtils.appendRefCondition(bean, joinPath, query, currentFilter) == false)
return;
if(orders!=null){
for(OrderField f:orders){
query.addOrderBy(f.isAsc(), f.getField());
}
}
String isManyToMany=this.keyOfJoinTable;
@SuppressWarnings("unchecked")
List<IQueryableEntity> subs = db.innerSelect(finalQuery, null, filters, option);
if(isManyToMany!=null) {
List<? extends IQueryableEntity> old=subs;
subs=new ArrayList<IQueryableEntity>();
for(IQueryableEntity d: old) {
IQueryableEntity realObj=(IQueryableEntity) ((VarObject)d).get(isManyToMany);
if(realObj==null) {
LogUtil.warn("Missing right record connect to {}, where {}",this.targetTableMeta.getTableName(false),query);
}else {
subs.add(realObj);
}
}
}
for (ISelectProvider reff : refs) { // 根据配置装填到对象中去
AbstractRefField refield = (AbstractRefField) reff;
Class<?> container = refield.getSourceFieldType();
if (refield.isSingleColumn()) {// 引用字段填充
Object value = SqlProcessor.collectValueToContainer(subs, container, ((ReferenceField) refield).getTargetField().fieldName());
refield.getField().set(obj, value);
} else { // 全引用填充
Object value;
if (targetTableMeta.getContainerType() == container) {
value = subs.isEmpty() ? null : subs.get(0);
} else {
value = DbUtils.toProperContainerType(subs, container,targetTableMeta.getContainerType(),refield);
}
refield.getField().set(obj, value);
}
}
// 反相关系
if (reverse != null) {
reverse.process(bean.getWrapped(), subs);
}
}
public Collection<String> getEffectFields() {
String[] str = new String[refs.size()];
for (int i = 0; i < refs.size(); i++) {
ISelectProvider p = refs.get(i);
str[i] = p.getName();
}
return Arrays.asList(str);
}
}