Hibernate QBC(Query By Criteria)

1.比较运算符
  HQL运算符               QBC(Query By Criteria)运算符                      含义
     =                     Restrictions.eq()                  等于
     <>                   Restrictions.not(Exprission.eq())  不等于
     >                     Restrictions.gt()                  大于
     >=                   Restrictions.ge()                  大于等于
     <                     Restrictions.lt()                  小于
     <=                   Restrictions.le()                  小于等于
     is null             Restrictions.isnull()              等于空值
     is not null      Restrictions.isNotNull()           非空值
     like                 Restrictions.like()                字符串模式匹配
     and                Restrictions.and()                 逻辑与
     and                Restrictions.conjunction()         逻辑与
     or                   Restrictions.or()                  逻辑或
     or                   Restrictions.disjunction()         逻辑或
     not                  Restrictions.not()                 逻辑非
     in(列表)          Restrictions.in()                  等于列表中的某一个值
     ont in(列表)         Restrictions.not(Restrictions.in())不等于列表中任意一个值
     between x and y      Restrictions.between()             闭区间xy中的任意值
     not between x and y  Restrictions.not(Restrictions..between()) 小于值X或者大于值y

2. 实体类:

public class DocumentInfo implements Serializable {
private Integer	                  documentId;
	private String	                  documentUrl;
	private String	                  documentName;
	private String	                  documentDescription;
	private Date	                  uploadTime;
	private Set<DocumentToRole>	 documentToRoles= new HashSet<DocumentToRole>();
	private Set<DocumentToDepartment> documentToDepartments = new HashSet<DocumentToDepartment>();
	private Set<UserVisitedDocument> userVisitedDocuments = new HashSet<UserVisitedDocument>();
//setter和getter方法....
}

 映射文件DocumentInfo.hbm.xml如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.reiyendms.model.pojo">
	<class name="DocumentInfo" table="document_info" >
		<id name="documentId" column="document_id" unsaved-value="null">
			<generator class="native" />
		</id>
		<property name="documentUrl" column="document_url" length="200" not-null="true" unique="true"/>
		<property name="documentName" column="document_name" length="100" />
		<property name="documentDescription" column="document_description" />
		<property name="uploadTime" column="upload_time" type="timestamp"/>
		<set name="documentToRoles" cascade="all"  inverse="true">
			<key column="document_id" />
			<one-to-many  class="DocumentToRole" />
		</set>
		<set name="documentToDepartments"  cascade="all" inverse="true" >
			<key column="document_id" />
			<one-to-many  class="DocumentToDepartment" />
		</set>
		<set name="userVisitedDocuments"  cascade="all" inverse="true" >
			<key column="document_id" />
			<one-to-many  class="UserVisitedDocument" />
		</set>
	</class>
</hibernate-mapping>

 3.一些查询实例

1).使用DetachedCriteria,在Service层构建好DetachedCriteria后,传入到Dao层进行查询:

private DetachedCriteria getDocQueryDC(DocumentSearchBean searchBean,
	                boolean isSortResult) {
		DetachedCriteria dc = DetachedCriteria.forClass(DocumentInfo.class);
                //去除重复记录
		dc.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		if (searchBean.getName() != null && !searchBean.getName().isEmpty()) {
			dc.add(Restrictions.ilike("documentName", searchBean.getName(),
			                MatchMode.ANYWHERE));
		}
		if (searchBean.getDescription() != null
		                && !searchBean.getDescription().isEmpty()) {
			dc.add(Restrictions.ilike("documentDescription", searchBean
			                .getDescription(), MatchMode.ANYWHERE));
		}
		if (searchBean.getSatrtDate() != null) {
			dc
			                .add(Restrictions.between("uploadTime", searchBean
			                                .getSatrtDate(), searchBean
			                                .getEndDate()));
		}
		if (searchBean.getRoleInfo() != null) {
			dc.setFetchMode("documentToRoles", FetchMode.JOIN); //1
			dc.createCriteria(("documentToRoles")).add(   Restrictions.eq("roleInfo", searchBean.getRoleInfo())); //2

                      // dc.createAlias("documentToRoles",
			// "dtr").add(Restrictions.eq("dtr.roleInfo",
			// searchBean.getRoleInfo())); //3
		}
		if (searchBean.getDeparts() != null
		                && searchBean.getDeparts().size() > 0) {
			dc.setFetchMode("documentToDepartments", FetchMode.JOIN);
			dc.createCriteria(("documentToDepartments")).add(
			                Restrictions.in("departmentInfo", searchBean
			                                .getDeparts()));
		}
//是否要排序
		if (isSortResult) {
			String sortName = searchBean.getSortName().trim();
			if (sortName != null && !sortName.isEmpty()) {
				if (searchBean.getSortOrder().equalsIgnoreCase("asc")) {
					dc.addOrder(Order.asc(sortName));
				}
				else {
					dc.addOrder(Order.desc(sortName));
				}
			}
			else {
				dc.addOrder(Order.desc("documentId"));
			}
		}
		return dc;
	}

 程序中标记为1,2的两句话与与被注释的标记为3的程序的效果是一样的,都会用inner join去查询,产生的sql语句如下:Hibernate: selectthis_.document_id as document1_1_1_, this_.document_url as document2_1_1_, this_.document_name as document3_1_1_,this_.document_description as document4_1_1_, this_.upload_time as upload5_1_1_, documentto1_.id as id3_0_, documentto1_.role_id
as role2_3_0_, documentto1_.document_id as document3_3_0_ from document_info this_ inner join document_to_role documentto1_ on  this_.document_id=documentto1_.document_id where documentto1_.role_id=? order by this_.document_id desc limit ?
 Dao层代码如下所示,使用了Spring的HibernateTemplate进行分布显示:

public List<DocumentInfo> getDocListForPage(final DetachedCriteria dc,
	                final int offset, final int length) {
		List<DocumentInfo> list = hibernateTemplate
		                .executeFind(new HibernateCallback() {

			                public Object doInHibernate(Session session)
			                                throws HibernateException,
			                                SQLException {
				                Criteria criteria = dc
				                              .getExecutableCriteria(session);
				                criteria.setFirstResult(offset);
				                criteria.setMaxResults(length);
				                return criteria.list();
			                }
		                });
		return list;
	}

如果是要得到总记录数的话,可以使用投影,如下所示:

 Criteria criteria = dc.getExecutableCriteria(session);
criteria.setProjection(Projections.rowCount());

 2). Restrictions.or操作:

两个条件或查询:
//相当于查找documentName like %str1% or uploadTime between date1 and date2

criteria.add(Restrictions.or(Restrictions.ilike("documentName", str1,MatchMode.ANYWHERE),Restrictions.between("uploadTime", date1,date2)));

 

三个或多个条件查询:(使用嵌套方式)

//相当于查找documentName like %str1% or uploadTime between date1 and date2 or documentId =4

criteria.add(Restrictions.or(Restrictions.ilike("documentName", str1,MatchMode.ANYWHERE),Restrictions.or(Restrictions.between("uploadTime", date1,date2), Restrictions.idEq(4))));

 3).Restrictions.not操作:  Restrictions.not(Restrictions.in())不等于列表中任意一个值

criteria.add(Restrictions.not(Restrictions.in("documentId", list)));

 它转换成sql 语句时,如下所示:

where not (this_.document_id in (?, ?, ?)) 

与我们一般的习惯写示: this_.document_id not in (?,?,?)有些区别,但效果是一样.

也可以直接使用Restrictions提供的sqlRestriction来达到同样的目的,sqlRestriction有三个重载类型:如下所示:

1.static Criterion sqlRestriction(String sql) :Apply a constraint expressed in SQL.
2.static Criterion sqlRestriction(String sql, Object[] values, Type[] types): Apply a constraint expressed in SQL, with the given JDBC parameters.
3.static Criterion sqlRestriction(String sql, Object value, Type type): Apply a constraint expressed in SQL, with the given JDBC parameter.

直接在Criteria中使用sql时,一定要特别注意使用别名,否则你会遇到一些异常:

如下所示:

DetachedCriteria dc = DetachedCriteria.forClass(DocumentInfo.class);
if (list != null && list.size() != 0) {
		String ids = list.toString().substring(1,
    list.toString().length() - 1);
		String sql = " document_id not in (" + ids + ") ";
		dc.add(Restrictions.sqlRestriction(sql));
}
Set<RoleInfo> roleInfos = searchBean.getRoleInfos();
		 if (roleInfos != null && roleInfos.size() != 0) {
				dc.setFetchMode("documentToRoles", FetchMode.JOIN);
				dc.createCriteria(("documentToRoles")).add(
				                Restrictions.in("roleInfo", roleInfos));
			}
........

 你会遇到如下异常:Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'document_id' in where clause is ambiguous

因为你进行关联查询时,它不知道document_id是document_info表中的 document_id还是document_to_role表中的,这时你就得使用别名,改成如下形式,就不会报错了:

DetachedCriteria dc = DetachedCriteria.forClass(DocumentInfo.class,"doc");
if (list != null && list.size() != 0) {
		String ids = list.toString().substring(1,
    list.toString().length() - 1);
		String sql = " doc.document_id not in (" + ids + ") ";
		dc.add(Restrictions.sqlRestriction(sql));
}

 但是如果你没有进行多表关联查询(也就是没有与其他对象进行关联查询),而只是进行了document_info表(DocumentInfo)的查询,那它就不会报前面的异常.

4.Subqueryes对象的使用:

 

复杂的查询使用criteria和subqueries可以达到很好的效果,先看看subquery:Factory class for criterion instances that represent expressions involving subqueries,使用Subquery时还有一个类一定会用到DetachedCriteria:

 

目标:统计某一专业的学生毕业人数

由于毕业涉及到学生课程学分的问题,所以就是课程表中的学分数值总数相等或则大于毕业要求学分,毕业学分这一栏在学生这一张表中。

首先生成一个DetachedCriteria实例:

DetachedCriteria dc=DetachedCriteria.forClass(Course.class);
dc.setProjection(Projections.count("CCredites"));

 之后生成一个criteria:

List<Student> l=session.createCriteria(Student.class,"s").add(Restrictions.eq("stuField", stuField)).add(Subqueries.propertyLe("graduateCount", dc)).list();

 最后我们看看这个发放的完整的形式:

@SuppressWarnings("unchecked")
 @Override
 public int countGraduateStudents(String stuField)//通过学生的专业查询一个专业的毕业人数
 {
  Session session=sessionFactory.openSession();
  DetachedCriteria dc=DetachedCriteria.forClass(Course.class);
  dc.setProjection(Projections.count("CCredites"));//获得一个DetachedCriteria
  List<Student> l=session.createCriteria(Student.class).add(Restrictions.eq("stuField", stuField)).add(Subqueries.propertyLe("graduateCount", dc)).list();//得到一个学生集合
  int inte=l.size();
  return inte;
 }

 

SQL:

Hibernate:
    select
        this_.ID_STU as ID1_0_0_,
        this_.STU_NAME as STU2_0_0_,
        this_.ID_STUDENTS as ID3_0_0_,
        this_.STU_PSD as STU4_0_0_,
        this_.STU_SIX as STU5_0_0_,
        this_.STU_FORM as STU6_0_0_,
        this_.STU_CLASS as STU7_0_0_,
        this_.STU_FIELD as STU8_0_0_,
        this_.STU_DATE_ENTER as STU9_0_0_,
        this_.STU_PUNISH as STU10_0_0_,
        this_.STU_GRADUATE as STU11_0_0_
    from
        students_course.student this_
    where
        this_.STU_FIELD=?
        and this_.STU_GRADUATE <= (
            select
                count(this0__.C_CREDITES) as y0_
            from
                students_course.course this0__
        )

 

由于使用了subqueries,我们就一次性的到数据库中查询,其实也可以用2个语句得到这个结果,但是那样的性能不是很好。

 

 

 

 

 

你可能感兴趣的:(DAO,spring,sql,Hibernate,jdbc)