hibernate的Criteria的一个bug HibernateXMLSQL单元测试.net
这个bug是在使用hibernate annotation过程中发现的,开始以为是hibenrate annotation的bug,后来又使用xml文件来配置,还是存在同样的问题。
问题场景:我需要使用省份与城市,他们的关系是:一个省有个多城市,很简单的OneToMany关系,在改变province中的cities的lazy特性时,遇到问题
由于我采用把所有的资源都是放在一个表中的策略,所有这里有一个基类Resource
基类
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CATEGORY_ID", discriminatorType = DiscriminatorType.STRING)
@Table(name = "T_RESOURCE")
public class Resource implements Serializable {
private String id;
private String name;
private ResourceCategory resourceCategory;
@Id
@GenericGenerator(name = "generator", strategy = "uuid")
@GeneratedValue(generator = "generator")
@Column(name = "ID")
public String getId() {
return id;
}
@Column(name = "NAME")
public String getName() {
return name;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CATEGORY_ID", updatable = false, insertable = false)
public ResourceCategory getResourceCategory() {
return resourceCategory;
}
@Override
public boolean equals(final Object other) {
if (!(other instanceof Resource))
return false;
Resource castOther = (Resource) other;
return new EqualsBuilder().append(id, castOther.id).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(id).toHashCode();
}
}
Province子类
@DiscriminatorValue("province")
public class Province extends Resource {
private Set<City> cities = new HashSet<City>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "province")
public Set<City> getCities() {
return cities;
}
}
子类City
@DiscriminatorValue("city")
public class City extends Resource {
private Province province;
public City(String name, ResourceCategory resourceCategory) {
super(name, resourceCategory);
}
@ManyToOne
@JoinColumn(name = "PARENT_ID")
public Province getProvince() {
return province;
}
}
hibernate.cfg.xml
<mapping resource="ResourceCategory.hbm.xml" />
<mapping resource="Resource.hbm.xml" />
-->
<mapping class="ResourceCategory" />
<mapping class="Resource" />
hibernate助手类
private static SessionFactory sessionFactory;
static {
// Configuration configuration = new Configuration();
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public Session getSession() {
return getSessionFactory().openSession();
}
}
单元测试类
public void testListProvinceByHQL() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction ctx = session.beginTransaction();
Query query = session.createQuery("from Province");
List<Province> provinces = query.list();
for (Province province : provinces) {
System.out.println(province.getName());
}
ctx.commit();
}
public void testListProvinceByCriteria() {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction ctx = session.beginTransaction();
Criteria criteria = session.createCriteria(Province.class);
List<Province> provinces = criteria.list();
for (Province province : provinces) {
System.out.println(province.getName());
}
ctx.commit();
}
}
分别执行单元测试方法,他们输出的sql语句是一样的,但是输出的结果是不一样的。
select this_.ID as ID1_1_, this_.NAME as NAME1_1_, this_.COMMENTS as COMMENTS1_1_, this_.CATEGORY_ID as CATEGORY2_1_1_, cities2_.PARENT_ID as PARENT5_3_, cities2_.ID as ID3_, cities2_.ID as ID1_0_, cities2_.NAME as NAME1_0_, cities2_.COMMENTS as COMMENTS1_0_, cities2_.CATEGORY_ID as CATEGORY2_1_0_, cities2_.PARENT_ID as PARENT5_1_0_ from T_RESOURCE this_ left outer join T_RESOURCE cities2_ on this_.ID=cities2_.PARENT_ID where this_.CATEGORY_ID='province'
testListProvinceByHQL方式输出的是
上海
上海
上海
上海
江苏
江苏
江苏
江苏
testListProvinceByCriteria方式输出的是
上海
江苏
若把public Set<City> getCities()的映射改为
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "province")
@Fetch(FetchMode.SELECT)
或者
@OneToMany(cascade = CascadeType.ALL, mappedBy = "province")
@LazyCollection(LazyCollectionOption.FALSE)
则两个方法输出sql语句是一样的,且结果也一样
SQL:
select this_.ID as ID1_0_, this_.COMMENTS as COMMENTS1_0_, this_.NAME as NAME1_0_, this_.CATEGORY_ID as CATEGORY1_1_0_ from T_RESOURCE this_ where this_.CATEGORY_ID='province'
select cities0_.PARENT_ID as PARENT5_1_, cities0_.ID as ID1_, cities0_.ID as ID1_0_, cities0_.COMMENTS as COMMENTS1_0_, cities0_.NAME as NAME1_0_, cities0_.CATEGORY_ID as CATEGORY1_1_0_, cities0_.PARENT_ID as PARENT5_1_0_ from T_RESOURCE cities0_ where cities0_.PARENT_ID=?
select cities0_.PARENT_ID as PARENT5_1_, cities0_.ID as ID1_, cities0_.ID as ID1_0_, cities0_.COMMENTS as COMMENTS1_0_, cities0_.NAME as NAME1_0_, cities0_.CATEGORY_ID as CATEGORY1_1_0_, cities0_.PARENT_ID as PARENT5_1_0_ from T_RESOURCE cities0_ where cities0_.PARENT_ID=?
输出:
上海
江苏
从上面的现象可是看出,不论配置文件怎么变化,通过hql语句获得结果一直不变,而Criteria会变化,这就证明了Criteria是有bug的。
据此我得出结论:hibernate的Criteria在把关联的lazy属性设置为"false",且把fetch设置为join时,查找数据就存在bug
后来我使用xml配置文件的方式,也存在同样的问题,也证明了我的这个结论,
Resource.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Resource"
table="T_RESOURCE">
<id name="id" type="string">
<column name="ID" />
</id>
<discriminator column="CATEGORY_ID" type="string" />
<property name="name" type="string" column="NAME" />
<many-to-one name="resourceCategory" insert="false"
update="false"
class="ResourceCategory"
column="CATEGORY_ID" />
<subclass name="Province"
discriminator-value="province"
推荐阅读
-
hibernate的Criteria的一个bug HibernateXMLSQL单元测试.net
-
一个伴随ASP.NET从1.0到4.0的OutputCache Bug介绍
-
一个伴随ASP.NET从1.0到4.0的OutputCache Bug介绍
-
Hibernate 读取文件到数据库的一个bug Hibernate
-
.net类库里ListView的一个BUG
-
ASP.NET Core针对一个使用HttpClient对象的类编写单元测试详解
-
碰到一个Hibernate的bug
-
.net类库里ListView的一个BUG
-
ASP.NET Core针对一个使用HttpClient对象的类编写单元测试详解