论坛首页 Java企业应用论坛

5种DAO查询方法的签名方式,哪个更好?

浏览 14960 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-01-12  
joyfun 写道
ibatis用的就是方法4  查询条件当对象传入 这样挺好的

这种方式主要是要写很多个条件参数的对象,我倒觉得这种方式是不太好的。
0 请登录后投票
   发表时间:2008-01-15  
暂时来看大家用4的可能性比较大,但是此种方案对于动态灵活性可能有待提高,此种方式对于代码中重复性代码会较多
0 请登录后投票
   发表时间: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)
0 请登录后投票
   发表时间: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,在实际应用中我发觉这种方式挺适用的。
0 请登录后投票
   发表时间:2008-01-26  
stamen 写道
  

    &nbsp;&nbsp;&nbsp;&nbsp;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
至于参数哪种好,我觉得除了那个参数一一写出来的,其他都还好
0 请登录后投票
   发表时间:2008-01-27  
我一般都是用的最后一种,用Criteria感觉和自己手工写没有多大区别。
只是想问问这个Where是如何设计的,不知可否讲解一下呢。
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间: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。。。
}


0 请登录后投票
   发表时间: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。。。
}


0 请登录后投票
   发表时间:2008-01-31  
通过Annotation的方法确实有点创意,不错啊。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics