0

我正忙于使用 hibernate 4.2.2.Final 和 Spring 3.2.3.RELEASE 编写应用程序。我使用日志框架 log4jdbc-remix (0.2.7) 来记录对数据库的所有 sql 调用。我正在使用休眠条件来生成 SQL 语句。在一种情况下,我正在生成一条 SQL 语句,当我在数据库本身 (DB/2) 上执行它时返回结果,只需从日志输出中复制粘贴即可。在休眠中,结果列表是空的(相同的查询)。

方法(我确实将变量的名称更改为更“通用的英语”名称):

@Override
public List<PersonId> getActiveNumbers(SpecialNumber specialumber) {
    final Criteria criteria = this.getCurrentSession().createCriteria(Person.class);
    criteria.add(Restrictions.eq("specialNr", specialNumber));
    criteria.setProjection(Projections.projectionList()
        .add(Projections.property("id.baseNr"))
        .add(Projections.property("id.subNr")));
    criteria.add(Subqueries.propertiesIn(new String[] { "id.baseNr", "id.subNr" },
        isActive()));
    criteria.setResultTransformer(Transformers.aliasToBean(PersonId.class));

    return (List<PersonId>) criteria.list();
}

private DetachedCriteria isActive() {
    DetachedCriteria isActive = DetachedCriteria.forClass(PersonSpecific.class);
    isActive.add(LocalDateComposite.lessThanOrEqual("date", LocalDate.now()));
    isActive.add(Restrictions.or(Restrictions.eq("dateCancel", null),
        Restrictions.ge("dateCancel", LocalDate.now())));
    isActive.setProjection(Projections.projectionList()
        .add(Projections.property("id.baseNr").as("baseNr"))
        .add(Projections.property("id.subNr").as("subNr")));
    return isActive;
}

但是,当我删除线

criteria.add(Restrictions.eq("specialNr", specialNumber));

hibernate 确实会生成一个结果列表。子查询“isActive”返回具有正确值的正确查询(根据日志,以及当我删除上述行时)。

“specialNr”是“specialNumber”类型,我有一个自定义的 UserType:

public class SpecialNumberUserType extends AbstractUserType implements UserType {
private static final int[] TYPES = { Types.BIGINT };

    [...]

@Override
public int[] sqlTypes() {
    return TYPES;
}

@Override
public Class<?> returnedClass() {
    return SpecialNumber.class;
 }

@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
    throws HibernateException, SQLException {
    if (rs.wasNull()) {
        return null;
    }
    return new specialNumber(rs.getLong(names[0]));
}

@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
    SessionImplementor session) throws HibernateException, SQLException {

    if (null == value) {
        st.setLong(index, 0L);
    } else {
        st.setLong(index, ((SpecialNumber) value).getValue());
    }

}
}

我无法弄清楚为什么休眠确实会生成正确的 sql,但无法获取正确的结果。我确实在其他表和查询中使用了“specialNumber”,它在其他查询中也有效。只有在这种特殊情况下,hibernate 才不会获取结果。有任何想法吗?感觉好像自定义用户类型 SpecialNumberUserType 有问题,但我不知道是什么,因为生成的 sql 显示了正确的值,并且它在使用相同的“specialNumber”类的其他 sql 语句中工作。

- 编辑:

我忘了提一下:当我对内存中的测试数据库(hsqldb)运行相同的方法时,我确实得到了预期的结果。所以,总结一下:

  1. 生成的 sql 没问题,值正确(检查日志);
  2. 直接在数据库(db/2终端)上运行生成的sql,得到了预期的结果;
  3. 对内存数据库运行方法“getActiveNumbers”,我得到了预期的结果;
  4. 对真实数据库运行方法“getActiveNumbers”,我得到一个空列表,这不是预期的结果。
  5. 运行相同的方法,但具有行 'criteria.add(Restrictions.eq("specialNr", specialNumber));' 删除,我确实得到了该查询的预期结果(这是相当多的行);
  6. 使用相同的“SpecialNumber”类作为另一个类的属性对真实数据库运行其他查询(使用休眠条件)确实有效 - 这里没有显示代码,但它非常相似,有一行像 'criteria.add(Restrictions. eq("specialNr", specialNumber));'.

我很困惑...

-- EDIT_II:

我正试图让它与 hql 查询一起使用。同样非常奇怪的问题,我只关注'specialNumber':

final Query query = this.getCurrentSession().createQuery(
        "select * from Person where specialNumber = 436260171");

给出预期的结果。(本例中有 2 条记录)。当我将其更改为:

final Query query = this.getCurrentSession().createQuery(
        "select * from Person where specialNumber = :specialNumber");
query.setLong("specialNumber", 436260171L);

或者

query.setParameter("specialNumber", new SpecialNumber(436260171L));

我再次得到一个空列表。所以,使用一个参数,突然间,它不再起作用了。我不明白:p。

4

1 回答 1

0

最后,解决了。显然在(旧版)数据库端,数据类型是 CHAR。在内存测试数据库中,类型被映射为整数。这就是为什么它“在内存中”工作,但不是在真正的数据库上工作。我不得不更改用户类型的 nullSafeSet 方法以使其正常工作......

编辑:更糟糕的是:“SpecialNumber”在不同的表中定义为不同的类型:在一个表上,它是一个 char(N),在另一个表上,它是一个 bigint。现在一切正常(我认为)。

于 2013-08-12T11:37:15.273 回答