锁定老帖子 主题:5种DAO查询方法的签名方式,哪个更好?
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-01-12
joyfun 写道 ibatis用的就是方法4 查询条件当对象传入 这样挺好的
这种方式主要是要写很多个条件参数的对象,我倒觉得这种方式是不太好的。 |
|
返回顶楼 | |
发表时间:2008-01-15
暂时来看大家用4的可能性比较大,但是此种方案对于动态灵活性可能有待提高,此种方式对于代码中重复性代码会较多
|
|
返回顶楼 | |
发表时间:2008-01-16
要说查询条件的对象化, 那肯定是4.
1,2,3没有什么区别, 5只是在namedparam比较有用. 问题是有的, 但我如果写dao的话, 还是会用3. 要说内存占用和工作效率, 多半应该是3好于4. 我认为真正的dao是没有业务逻辑,只是怎么和数据库对话而已. 在已经有了hibernate/jpa/jdbctemplate的情况下, 这种东西实在没必要人去做. 除非数据库压根没可能对象化. 撇开dao不谈, 要说查询的方式, 我喜欢这样的方式: public interface PersonAccess { @Finder(query="from Person where firstName = :firstName") Person find(@Named("firstName") String name); } 翻页: public interface PersonAccess { @Finder(query="from Person") List<Person> listAll(@FirstResult int first, @MaxResults int max); } 接口已经完全说明怎么查询了,其实现的单例动态生成就可以了.asm+guice/cglib. (http://www.wideplay.com/dynamicfinders) |
|
返回顶楼 | |
发表时间:2008-01-21
b051 写道 要说查询条件的对象化, 那肯定是4.
1,2,3没有什么区别, 5只是在namedparam比较有用. 问题是有的, 但我如果写dao的话, 还是会用3. 要说内存占用和工作效率, 多半应该是3好于4. 我认为真正的dao是没有业务逻辑,只是怎么和数据库对话而已. 在已经有了hibernate/jpa/jdbctemplate的情况下, 这种东西实在没必要人去做. 除非数据库压根没可能对象化. 撇开dao不谈, 要说查询的方式, 我喜欢这样的方式: public interface PersonAccess { @Finder(query="from Person where firstName = :firstName") Person find(@Named("firstName") String name); } 翻页: public interface PersonAccess { @Finder(query="from Person") List<Person> listAll(@FirstResult int first, @MaxResults int max); } 接口已经完全说明怎么查询了,其实现的单例动态生成就可以了.asm+guice/cglib. (http://www.wideplay.com/dynamicfinders) 翻页查询我一般直接用JDBC,这样更灵活更高效,一般只对单条记录操作使用Hibernate,在实际应用中我发觉这种方式挺适用的。 |
|
返回顶楼 | |
发表时间:2008-01-26
stamen 写道 DAO层除了CRUD的数据操作外,另一个重要的操作就是根据查询条件执行数据查询,不同的ORM框架都允许用户动态绑定参数确定查询条件。查询条件项的数目往往是不固定的,如既可能要求以userName为条件查询User,也可能要求以userName+status等组合条件查询User。条件项数目的不定性给查询接口方法的设计造成为一定的困难,实体DAO定义带参的查询方法时,一般有5种方式,下面分别对这些方法进行介绍。 参数不稳定,同样你的语句也会不稳定啊,比如userName+status的情况,就会成为where userName=? or status=?,楼主怎么没有讨论这种情况呢?这样的话,方法中传入语句就不行了。再者,你的查找方法为什么要传入语句呢,像List findOrder(String hql,Object[] params),难道你还在DAO的外面去拼sql?而且怎么看findOrder也不是basedao里的,传入语句就没有道理了。楼主最好说清楚这里讨论的是basedao还是继承的dao 我觉得楼主讨论的更像是DAO的查询方法的参数该怎样写,既清晰又简单。根据以上分析,应该变成这样: List findOrder(String hql,Object[] params) --> List findOrder(Object[] params) 方法里面,就可以根据情况使用hql、sql或Criteria 至于参数哪种好,我觉得除了那个参数一一写出来的,其他都还好 |
|
返回顶楼 | |
发表时间:2008-01-27
我一般都是用的最后一种,用Criteria感觉和自己手工写没有多大区别。
只是想问问这个Where是如何设计的,不知可否讲解一下呢。 |
|
返回顶楼 | |
发表时间:2008-01-28
List<Order> orderList = new service.queryList(Order.class,new HashMap(){{ put("type.name","=新订单"); put("createdDate","bewteen 2008-01-01 and 2008-01-30"); put("orderBy.name","=张三"); }}); 写一个CreteriaUtils将 =,>,like条件等转换为hibernate的Creteria |
|
返回顶楼 | |
发表时间:2008-01-30
我目前的写法,只是感到不够灵活,到不够用的时候再想办法重构好了。。
@Target( { ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface SQLQuery { /** * 与查询参数对应的SQL片段的数组<br> * 数组长度=1:此SQL片段被插入到SQL查询语句中,实际参数值添加到与?对应的位置。<br> * 数组长度=2:此SQL片段被插入到SQL查询语句中,实际参数类型应该是Boolean,<br> * 当实参=true,插入第一个SQL片段,实参=false,插入第二个SQL片段 * * @return */ String[] value() default {}; } public class QueryBuilder { // 生成的SQL语句 StringBuilder sql = new StringBuilder(); // sql中与‘?’匹配的参数 List<Object> params = new ArrayList<Object>(); /** * 构建查询语句<br> * * 例子:QueryBuilder builder = new QueryBuilder();<br> * builder.setSql(buf);<br> * builder.setParams(params);<br> * builder.build(QueryArgs.class, args); * * @param clazz * 用注解标识的查询参数类 * @param args * 查询参数对象,可以是查询参数类的实例,<br> * 也可以仅仅是一个map,只要符合OGNL读取数据的方式。 * @return */ public StringBuilder build(Class<?> clazz, Object args) { // 如果没有传递实际参数,则忽略此次构建 if (args == null) return sql; for (Field field : clazz.getDeclaredFields()) { SQLQuery query = field.getAnnotation(SQLQuery.class); // 非查询字段,跳到下一个 if (query == null) continue; try { Object value = Ognl.getValue(field.getName(), args); // 查询字段空缺的,跳到下一个 if (value == null || (value instanceof String && StringUtils.isEmpty(value.toString()))) continue; // query.value().length所表示的含义参考SQLQuery注解 if (query.value().length == 1) { sql.append(query.value()[0]); params.add(value); } else if (query.value().length >= 2) sql.append(Boolean.valueOf(value.toString()) ? query.value()[0] : query.value()[1]); // query.value().length==0,跳到下一个 } catch (Exception e) { log.warn("处理查询参数失败,该参数被忽略:" + field.getName()); continue; } } return sql; } //省略其他部分。。。。 } public class QueryArgs { // 受理码 @SQLQuery(" and a.acceptCode=?") String acceptCode; // 项目类型 @SQLQuery(" and a.definition.id=?") Long definitionId; // 申请人姓名,模糊查询 @SQLQuery(" and a.proposer.name like '%'+?+'%'") String proposerName; // 受理时间范围1 @SQLQuery(" and a.acceptTime >= ?") Date beginTime; // 受理时间范围2 @SQLQuery(" and a.acceptTime <= ?") Date endTime; // 是否已经办结,如果未指定,则包括全部项目 @SQLQuery( { " and a.finishedTime is not null", " and a.finishedTime is null" }) Boolean m_finished; // 假想的finished参数,供页面使用, // 因为struts2将0长度字符串传入Boolean的时候,转成了false,下面是为解决这个问题 public void setFinished(String finished) { m_finished = StringUtils.isEmpty(finished) ? null : Boolean.valueOf(finished); } // 承办单位id @SQLQuery(" and a.definition.department.id=?") Long departmentId; //省略若干getter、setter。。。 } |
|
返回顶楼 | |
发表时间:2008-01-30
我目前的写法,只是感到不够灵活,到不够用的时候再想办法重构好了。。
@Target( { ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) public @interface SQLQuery { /** * 与查询参数对应的SQL片段的数组<br> * 数组长度=1:此SQL片段被插入到SQL查询语句中,实际参数值添加到与?对应的位置。<br> * 数组长度=2:此SQL片段被插入到SQL查询语句中,实际参数类型应该是Boolean,<br> * 当实参=true,插入第一个SQL片段,实参=false,插入第二个SQL片段 * * @return */ String[] value() default {}; } public class QueryBuilder { // 生成的SQL语句 StringBuilder sql = new StringBuilder(); // sql中与‘?’匹配的参数 List<Object> params = new ArrayList<Object>(); /** * 构建查询语句<br> * * 例子:QueryBuilder builder = new QueryBuilder();<br> * builder.setSql(buf);<br> * builder.setParams(params);<br> * builder.build(QueryArgs.class, args); * * @param clazz * 用注解标识的查询参数类 * @param args * 查询参数对象,可以是查询参数类的实例,<br> * 也可以仅仅是一个map,只要符合OGNL读取数据的方式。 * @return */ public StringBuilder build(Class<?> clazz, Object args) { // 如果没有传递实际参数,则忽略此次构建 if (args == null) return sql; for (Field field : clazz.getDeclaredFields()) { SQLQuery query = field.getAnnotation(SQLQuery.class); // 非查询字段,跳到下一个 if (query == null) continue; try { Object value = Ognl.getValue(field.getName(), args); // 查询字段空缺的,跳到下一个 if (value == null || (value instanceof String && StringUtils.isEmpty(value.toString()))) continue; // query.value().length所表示的含义参考SQLQuery注解 if (query.value().length == 1) { sql.append(query.value()[0]); params.add(value); } else if (query.value().length >= 2) sql.append(Boolean.valueOf(value.toString()) ? query.value()[0] : query.value()[1]); // query.value().length==0,跳到下一个 } catch (Exception e) { log.warn("处理查询参数失败,该参数被忽略:" + field.getName()); continue; } } return sql; } //省略其他部分。。。。 } public class QueryArgs { // 受理码 @SQLQuery(" and a.acceptCode=?") String acceptCode; // 项目类型 @SQLQuery(" and a.definition.id=?") Long definitionId; // 申请人姓名,模糊查询 @SQLQuery(" and a.proposer.name like '%'+?+'%'") String proposerName; // 受理时间范围1 @SQLQuery(" and a.acceptTime >= ?") Date beginTime; // 受理时间范围2 @SQLQuery(" and a.acceptTime <= ?") Date endTime; // 是否已经办结,如果未指定,则包括全部项目 @SQLQuery( { " and a.finishedTime is not null", " and a.finishedTime is null" }) Boolean m_finished; // 假想的finished参数,供页面使用, // 因为struts2将0长度字符串传入Boolean的时候,转成了false,下面是为解决这个问题 public void setFinished(String finished) { m_finished = StringUtils.isEmpty(finished) ? null : Boolean.valueOf(finished); } // 承办单位id @SQLQuery(" and a.definition.department.id=?") Long departmentId; //省略若干getter、setter。。。 } |
|
返回顶楼 | |
发表时间:2008-01-31
通过Annotation的方法确实有点创意,不错啊。
|
|
返回顶楼 | |