2015-12-09 65 views
3

我不得不使用createSQLQuery将值插入带有使用hibernate的Identity列(第一列和主键)的表中。使用休眠类不是一种选择,因为这些表是为添加到系统中的每个客户实时创建的。我已经运行了查询并成功插入到表中。然后我执行一个“select scope_identity()”,它总是返回null。 “select @@ Identity”起作用,但不能保证是正确的。我也尝试追加“select scope_identity()”到插入查询。然后我试图query.list()query.uniqueResult()这两个抛出的休眠异常“无结果...”在休眠时使用createSQLQuery选择scope_identity()

Session session = DatabaseEngine.getSessionFactory().openSession(); 
    String queryString = "insert into table1 (dataid) values (1)" 
    SQLQuery query = session.createSQLQuery(insertQueryString); 
    query.executeUpdate(); 
    query = session.createSQLQuery("select scope_identity()"); 
    BigDecimal entryID = (BigDecimal)query.uniqueResult(); 

这个简单的例子表的定义如下:

"CREATE TABLE table1 (EntryID int identity(1,1) NOT NULL," + 
    "DataID int default 0 NOT NULL, " + 
    "PRIMARY KEY (EntryID))"; 

有没有办法,我缺少使用scope_identity()与createSQLQuery

回答

1

实际上Hibernate使用的SQLServerDialect类也使用相同的“scope_identity()”。

它不工作的原因是因为您需要在同一个语句或存储过程中执行这些操作。 如果您在单独的语句中执行scope_identity()调用,SQL Server将无法为您提供上次插入的标识值。

你不能用SQLQuery这样做,即使Hibernate使用JDBC来完成这个任务。我写了一个测试在GitHub上仿效这一点,它的工作原理是这样的:

Session session = entityManager.unwrap(Session.class); 
final AtomicLong resultHolder = new AtomicLong(); 
session.doWork(connection -> { 
    try(PreparedStatement statement = connection.prepareStatement("INSERT INTO post VALUES (?) select scope_identity() ")) { 
     statement.setString(1, "abc"); 
     if (!statement.execute()) { 
      while (!statement.getMoreResults() && statement.getUpdateCount() != -1) { 
       // do nothing until we hit the resultset 
      } 
     } 
     try (ResultSet rs = statement.getResultSet()) { 
      if(rs.next()) { 
       resultHolder.set(rs.getLong(1)); 
      } 
     } 
    } 
}); 
assertNotNull(resultHolder.get()); 

该代码使用Java 8 Lambda表达式,而不是匿名类的,但你可以很容易移植到Java的1.7了。