论坛首页 Java企业应用论坛

请问该如何优化这段逻辑:根据搜索条件查找相应的对象实体

浏览 5618 次
精华帖 (0) :: 良好帖 (8) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-04-21  
有一个简单的需求:Product是一个实体类,用户在搜索页面上输入Product的属性值,系统根据这些属性值找到符合条件的Product并列举出来。搜索的代码如下:

	String getLikeCondition(String condition) {
		return "%" + condition + "%";
	}

	@SuppressWarnings("unchecked")
	public List<Product> getProducts(final Map<String, String> conditions) {
		final StringBuffer hql = new StringBuffer("from Product p where 1=1");
		for(String key : conditions.keySet()) {
			if (key.equalsIgnoreCase("name"))
				hql.append(" and p.name like :name");
			if (key.equalsIgnoreCase("category"))
				hql.append(" and p.category.name like :category");
			if (key.equalsIgnoreCase("priceLowerBound")) {
				int priceLowerBound = Integer.parseInt(conditions.get(key));
				if (priceLowerBound > 0)
					hql.append(" and p.price > :priceLowerBound");
			}
			if (key.equalsIgnoreCase("priceUpperBound")) {
				int priceUpperBound = Integer.parseInt(conditions.get(key));
				if (priceUpperBound > 0)
					hql.append(" and p.price <= :priceUpperBound");
			}
			//Other conditions omitted
		}

		return (List<Product>) getHibernateTemplate().execute(new HibernateCallback() {
		    public Object doInHibernate(Session session) throws HibernateException {
		        Query query = session.createQuery(hql.toString());
						for(String key : conditions.keySet()) {
							if (key.equalsIgnoreCase("name"))
								query.setParameter("name", getLikeCondition(conditions.get("name")));
							if (key.equalsIgnoreCase("category"))
								query.setParameter("category", getLikeCondition(conditions.get("category")));
							if (key.equalsIgnoreCase("priceLowerBound")) {
								int priceLowerBound = Integer.parseInt(conditions.get(key));
								if (priceLowerBound > 0)
									query.setParameter("priceLowerBound", (float)priceLowerBound);
							}
							if (key.equalsIgnoreCase("priceUpperBound")) {
								int priceUpperBound = Integer.parseInt(conditions.get(key));
								if (priceUpperBound > 0)
									query.setParameter("priceUpperBound", (float)priceUpperBound);
							}
							//Other conditions omitted
						}
		        List<Product> items = (List<Product>)query.list();
		        return items;
		    }
		});

	}


方法getProducts接受一个类型为Map<String, String>的参数conditions,该参数是一个<属性,属性值>列表,在方法中分析这个列表并组合成查询条件,最后执行查询并返回符合条件的Product列表

让人不爽的是代码中使用了很多if判断,而且使用了两次循环。是否有更好的办法来简化这段代码呢?或者有没有更好的方式来实现这个需求?
   发表时间:2008-04-21  
哎呀,应该发到入门讨论版的,一时手快了~~~
0 请登录后投票
   发表时间:2008-04-22  
用criteria
0 请登录后投票
   发表时间:2008-04-22  
我原本就是用Criteria来做的:

	public List<Product> getProducts(final Map<String, String> conditions) {

		final DetachedCriteria query = DetachedCriteria.forClass(Product.class);
		for(String key : conditions.keySet()) {
			if (key.equalsIgnoreCase("name"))
				query.add(Restrictions.like(key, conditions.get(key), MatchMode.ANYWHERE));
			if (key.equalsIgnoreCase("category"))
				query.add(Restrictions.like("category.name", conditions.get(key), MatchMode.ANYWHERE));
			if (key.equalsIgnoreCase("priceLowerBound")) {
				int priceLowerBound = Integer.parseInt(conditions.get(key));
				if (priceLowerBound > 0)
					query.add(Restrictions.gt("price", (float)priceLowerBound));
			}
			if (key.equalsIgnoreCase("priceUpperBound")) {
				int priceUpperBound = Integer.parseInt(conditions.get(key));
				if (priceUpperBound > 0)
					query.add(Restrictions.le("price", (float)priceUpperBound));
			}
			//Other code omitted

		}
		//Line 22

		return (List<Product>) getHibernateTemplate().execute(new HibernateCallback() {
		    public Object doInHibernate(Session session) throws HibernateException {
		        Criteria criteria = query.getExecutableCriteria(session);
		        List<Product> items = (List<Product>)criteria.list();
		        return items;
		    }
		});


发现Hibernate使用了left outer join来读取关联对象,这可能导致比较严重的性能问题,所以才尝试问题中的代码。但发现使用Query来查询还是使用了left outer join来读取关联对象。找了一下资料,Criteria提供了setFetchMode方法来设置抓取模式,于是在上面代码的第22行加上如下代码:

query.setFetchMode("category", FetchMode.SELECT);


果然,Hibernate使用单独的select语句来读取关联对象了(而且,如果程序中不访问这个关联对象,该条语句是不会执行的)

但似乎还是有如下两个问题:
1.如果某个关联对象没有设置fetch mode为SELECT,Hibernate还是会用left outer join读取它(就算我在查询条件中并没有使用该属性)
2.就算是设置了某关联对象的fetch mode为SELECT,但读取该关联对象的关联对象还是会用left outer join。这个太让人郁闷了:我不大可能把与Product级联关联的对象都设一下fetch mode吧?
对这两个问题,特别是第2个问题有没有好的办法来解决呢?
0 请登录后投票
   发表时间:2008-04-28  
关联对象的默认设置就是fetch="select",你是不是没有使用lazy loading?
0 请登录后投票
   发表时间:2008-09-10  
还是用DetachedCriteria
在业务层action中设个专门的方法composeDC组织DetachedCriteria
0 请登录后投票
论坛首页 Java企业应用版

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