S.O.D.A理解
S.O.D.A. 全称 Simple Object Database Access
Simple Object Database Access(S.O.D.A)API是Carl Rosenberger创建的,他也是db4o的创建者
S.O.D.A. 是用于数据库交流的对象接口(API).
目前S.O.D.A.只定义了查询接口,由以下几个接口组成:
Constraint(定义了约束)
Constraints(约束的集合)
Query(定义了查询节点)
Candidate(封装了查询结果对象用于在Evaluation中调用)
Evaluation(用在查询最后被回调来筛选数据)
ObjectContainer(定义数据容器,用于生成Query)
ObjectSet(Query返回的结果集)
运用S.O.D.A,你可以动态地构建查询。查询API的基本框架就是查询图表(query graph)。
查询图表(query graph)这个词就很形象的描述了S.O.D.A.所需要的数据结构.
一开始我是以树的方式去理解S.O.D.A.的结构,虽然是可以这样实现这个接口但最后去解析计算其树的路径就极其复杂.
既然计算树的路径复杂,那就不去计算,一开始就以一个约定的方式保存好路径,直接使用这个路径就可以了.
这样这个结构就变成一个图表的形式的,比如Query可以看成图表中的一条记录,Query通过不断descend指定的节点路径就相当于表的序号,Query通过constrain约束的条件就是一条记录的内容,而Constraint之间的and/or关系就是记录之间的关系,这样比较容易就可以实现S.O.D.A了
思想是,将这个查询图表(这里是一个Map),不断的通过descend传承下去,所有的Constraint和节点路径都放在查询图表中,而最后只要取出查询图表,那所有的关系都一目了然了.
这里附上一个简单的实现代码:
Query 的实现:
/** * 面向DAO的,采用SODA方式进行查询 此Query的用法和标准的SODA稍有不同 * 此Query不能指定根查询节点的约束.此节点的约束由DAO指定(因为DAO使用了泛型,若此处指定的话,泛型cast的时候就会抛CastError的异常) * * @author Kevin.Huang * @date 2007-9-30 */ public class ZQuery implements Query { /** * 此节点对应的域 */ private String field = null; /** * 所有的约束的集合 */ private MultiMap constraints; private List< ZOrder > orders; private List< ZComparator > comparators; /** * 父节点 */ private ZQuery parentQuery; /** * 子节点 */ private Map< String, ZQuery > querys = new HashMap< String, ZQuery >(); public ZQuery() { this.constraints = new MultiValueMap(); this.orders = new ArrayList< ZOrder >(); this.comparators = new ArrayList< ZComparator >(); } protected ZQuery(String field, ZQuery parentQuery) { this.field = field; this.parentQuery = parentQuery; this.constraints = parentQuery.getConstraint(); this.orders = parentQuery.getOrders(); this.comparators = parentQuery.getComparators(); } public Constraint constrain(Object constraint) { if (field == null) { throw new RuntimeException("The Root Query Node can constraint only one condition!"); } ZConstraint c = new ZConstraint(this, constraint); constraints.put(this.field, c); return c; } @SuppressWarnings("unchecked") public Constraints constraints() { return new ZConstraints((Collection< ZConstraint >) constraints.get(this.field)); } public Query descend(String fieldName) { if (querys.keySet().contains(fieldName)) { return querys.get(fieldName); } else { ZQuery q = new ZQuery((this.field == null ? fieldName : (this.field + "." + fieldName)), this); querys.put(fieldName, q); return q; } } public Query orderAscending() { if (field == null) { throw new RuntimeException("The Root Query Node cannot make order!"); } this.orders.add(new ZOrder(this.field, true)); return this; } public Query orderDescending() { if (field == null) { throw new RuntimeException("The Root Query Node cannot make order!"); } this.orders.add(new ZOrder(this.field, false)); return this; } @SuppressWarnings("unchecked") public Query sortBy(Comparator comparator) { this.comparators.add(new ZComparator(this.field, comparator)); return this; } /** * @return the field */ public String getField() { return field; } /** * @return the constraints */ public MultiMap getConstraint() { return constraints; } /** * @return the querys */ public Map< String, ZQuery > getQuerys() { return querys; } /** * @return the parentQuery */ public ZQuery getParentQuery() { return parentQuery; } /** * @return the orders */ public List< ZOrder > getOrders() { return orders; } /** * @return the comparators */ public List< ZComparator > getComparators() { return comparators; } }
Constraint的实现:
/** * @author Kevin.Huang * @date 2007-9-30 */ public class ZConstraint implements Constraint { /** * constant defination : value of "=" sql operator */ public static final String EQUAL = "equal"; /** * constant defination: value of "!=" sql operator */ public static final String NOT = "not"; /** * constant defination: value of ">=" sql operator */ public static final String GREATER = "greater"; /** * constant defination: value of "<=" sql operator */ public static final String SMALLER = "smaller"; /** * constant defination: value of "between" sql operator */ public static final String CONTAINS = "contains"; /** * constant defination: value of "like" sql operator */ public static final String LIKE = "like"; /** * constant defination: value of "startsWith" sql operator */ public static final String STARTSWITH_TRUE = "startsWith:true"; /** * constant defination: value of "startsWith" sql operator */ public static final String STARTSWITH_FALSE = "startsWith:false"; /** * constant defination: value of "endsWith" sql operator */ public static final String ENDSWITH_TRUE = "endsWith:true"; /** * constant defination: value of "endsWith" sql operator */ public static final String ENDSWITH_FALSE = "endsWith:false"; /** * 此约束所在的Query节点 */ private ZQuery query; /** * 次约束的基准值 */ private Object value; private List< ZConstraintLink > zConstraintLinks = new ArrayList< ZConstraintLink >(); /** * 关联的约束 */ private Collection< String > conditions = new ArrayList< String >(); protected ZConstraint(ZQuery query, Object value) { this.query = query; this.value = value; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#and(com.infowarelab.zephyr.domain.soda.Constraint) */ public Constraint and(Constraint with) { zConstraintLinks.add(new ZConstraintLink(ZConstraintLink.TYPE_AND, (ZConstraint) with)); return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#contains() */ public Constraint contains() { String[] c = {NOT }; if (conflictOnly(c)) { throw new ConstraintConditionWrongException("contains only can with not!"); } this.conditions.add(CONTAINS); return this; } public Constraint endsWith(boolean caseSensitive) { String[] c = {NOT }; if (conflictOnly(c)) { throw new ConstraintConditionWrongException("endsWith only can with not!"); } if (caseSensitive) { this.conditions.add(ENDSWITH_TRUE); } else { this.conditions.add(ENDSWITH_FALSE); } return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#equal() */ public Constraint equal() { String[] c = {EQUAL, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE, STARTSWITH_TRUE }; if (conflictExist(c)) { throw new ConstraintConditionWrongException( "equal can't with contains , endsWith, startsWith, like or himself!"); } this.conditions.add(EQUAL); return this; } /** * @return the conditions */ public Collection< String > getConditions() { return conditions; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#getObject() */ public Object getObject() { return this.value; } /** * @return the query */ public ZQuery getQuery() { return query; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#greater() */ public Constraint greater() { String[] c = {GREATER, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE, STARTSWITH_TRUE }; if (conflictExist(c)) { throw new ConstraintConditionWrongException( "greater can't with contains , endsWith, startsWith, like or himself!"); } this.conditions.add(GREATER); return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#like() */ public Constraint like() { String[] c = {NOT }; if (conflictOnly(c)) { throw new ConstraintConditionWrongException("like only can with not!"); } this.conditions.add(LIKE); return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#not() */ public Constraint not() { if (conditions.contains(NOT)) { throw new ConstraintConditionWrongException("not already exist!"); } this.conditions.add(NOT); return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#or(com.infowarelab.zephyr.domain.soda.Constraint) */ public Constraint or(Constraint with) { zConstraintLinks.add(new ZConstraintLink(ZConstraintLink.TYPE_OR, (ZConstraint) with)); return this; } /* * (non-Javadoc) * * @see com.infowarelab.zephyr.domain.soda.Constraint#smaller() */ public Constraint smaller() { String[] c = {SMALLER, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE, STARTSWITH_TRUE }; if (conflictExist(c)) { throw new ConstraintConditionWrongException( "Smaller can't with contains ,endsWith, startsWith, like or himself!"); } this.conditions.add(SMALLER); return this; } public Constraint startsWith(boolean caseSensitive) { String[] c = {NOT }; if (conflictOnly(c)) { throw new ConstraintConditionWrongException("endsWith only can with not!"); } if (caseSensitive) { this.conditions.add(STARTSWITH_TRUE); } else { this.conditions.add(STARTSWITH_FALSE); } return this; } private boolean conflictExist(String[] conditionStrings) { for (String conditionString : conditionStrings) { if (conditions.contains(conditionString)) { return true; } } return false; } private boolean conflictOnly(String[] conditionStrings) { for (String existCondition : conditions) { for (String conditionString : conditionStrings) { if (existCondition.equals(conditionString)) { return true; } } } return false; } /** * @return the zConstraintLinks */ public List< ZConstraintLink > getZConstraintLinks() { return zConstraintLinks; } }