获取具有 uniqueidentifier 主键的实体时出现问题
为了调查 Hibernate 的行为是否与 NHibernate 的针对特定使用场景不同,我开始编写一个 Java SE &我的基于 NHibernate 的应用程序的相关部分的 Hibernate 端口,但在获取实体时遇到了问题,其中相应的 SQL Server 2008 R2 Express 表使用 uniqueidentifier
作为主键。
这是映射文件:
<!-- User.hbm.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernatetest.entity.User" table="aspnet_Users">
<id name="Id">
<column name="UserId" sql-type="uniqueidentifier" not-null="true" />
</id>
<!-- ... -->
以及相应的 POJO 定义:
// hibernatetest/entity/User.java
package hibernatetest.entity;
import java.util.UUID;
public class User {
private UUID id;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
//...
以及主要代码:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
User currentUser = (User) session.get(User.class, UUID.fromString("473D248D-8D91-41C9-BD73-8ACA45539D79"));
问题是对 Session#get 的调用返回 null
,因为它无法找到主键 '473D248D 的用户实体-8D91-41C9-BD73-8ACA45539D79'
。
当我启用完整日志记录时,我看到:
DEBUG [main] (AbstractBatcher.java:401) - select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
Hibernate: select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
TRACE [main] (NullableType.java:133) - binding '2c6d8085f3f2808eeae1f6e1aef5f4e9ecaed5d5c9c43c19837718ed05af828082ca808cece5e1f3f4d3e9e7c2e9f4f3ca808bedeff3f4d3e9e7c2e9f4f3f8f03df30a4ac5d31df9c7bda40d0d11c149' to parameter: 1
我不知道 Hibernate 如何派生值 '2c6d8085f...
,但这不是我期望的值绑定,并且它阻止用户实体被定位。
如果我将 hibernatetest.entity.User
的 id
字段的类型从 java.util.UUID
更改为 String
,则此行成功找到实体:
User currentUser = (User) session.get(User.class, "473D248D-8D91-41C9-BD73-8ACA45539D79");
日志输出变为:
DEBUG [main] (AbstractBatcher.java:401) - select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
Hibernate: select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
TRACE [main] (NullableType.java:133) - binding '473D248D-8D91-41C9-BD73-8ACA45539D79' to parameter: 1
How did Hibernatecalculate the value '2c6d8085f...
to Bind for the UUID '473D248D-8D91-41C9- BD73-8ACA45539D79'
?如何让它绑定实际的 UUID 值?
In order to investigate whether Hibernate's behavior is different than NHibernate's for a particular usage scenario, I began writing a Java SE & Hibernate port of the relevant parts of my NHibernate-based application, but encountered a problem with obtaining an entity where the corresponding SQL Server 2008 R2 Express table uses a uniqueidentifier
for the primary key.
Here's the mapping file:
<!-- User.hbm.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernatetest.entity.User" table="aspnet_Users">
<id name="Id">
<column name="UserId" sql-type="uniqueidentifier" not-null="true" />
</id>
<!-- ... -->
And corresponding POJO definition:
// hibernatetest/entity/User.java
package hibernatetest.entity;
import java.util.UUID;
public class User {
private UUID id;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
//...
And main code:
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
User currentUser = (User) session.get(User.class, UUID.fromString("473D248D-8D91-41C9-BD73-8ACA45539D79"));
The problem is that the call to Session#get returns null
, as it fails to find the user entity for primary key '473D248D-8D91-41C9-BD73-8ACA45539D79'
.
When I enable full logging, I see:
DEBUG [main] (AbstractBatcher.java:401) - select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
Hibernate: select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
TRACE [main] (NullableType.java:133) - binding '2c6d8085f3f2808eeae1f6e1aef5f4e9ecaed5d5c9c43c19837718ed05af828082ca808cece5e1f3f4d3e9e7c2e9f4f3ca808bedeff3f4d3e9e7c2e9f4f3f8f03df30a4ac5d31df9c7bda40d0d11c149' to parameter: 1
I don't know how Hibernate derived the value '2c6d8085f...
, but this is not the value binding that I expected, and it prevents the user entity from being located.
If I change the type of the id
field of hibernatetest.entity.User
from java.util.UUID
to String
, then this line succeeds in finding the entity:
User currentUser = (User) session.get(User.class, "473D248D-8D91-41C9-BD73-8ACA45539D79");
And the log output becomes:
DEBUG [main] (AbstractBatcher.java:401) - select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
Hibernate: select user0_.UserId as UserId0_0_ from aspnet_Users user0_ where user0_.UserId=?
TRACE [main] (NullableType.java:133) - binding '473D248D-8D91-41C9-BD73-8ACA45539D79' to parameter: 1
How did Hibernate calculate the value '2c6d8085f...
to bind for the UUID '473D248D-8D91-41C9-BD73-8ACA45539D79'
? How can I make it bind the actual UUID value instead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Java
UUID
(java.util.UUID
) 和 SQL Serveruniqueidentifier
是两个不同的东西。您正在告诉 Hibernate 在两者之间进行映射。我很惊讶 Hibernate 能够做任何事情,并且对于它生成的东西非常奇怪并不感到惊讶。据我所知(对 SQL Server 没有做太多工作)Hibernate 会将
uniqueidentifier
视为普通的旧字符串列。因此,最好的选择可能是将其映射为字符串。您仍然可以使用getUUID()
和setUUID()
...只需确保您正在执行基于属性的映射,Hibernate 知道 UUID 字段是一个瞬态字段,并且不会尝试同时存储 ID 和 UUID。
SQL Server 可能有某种特殊的 UUID 类,您可以在 Java 中使用它来与 Java UUID 相互转换。也有可能 Hibernate 的某些新版本已经支持将 java.util.UUID 映射到 SQL Server 的 UUID,但我认为这两种可能性都不成立。
编辑:进一步研究问题后,我可以看到您的一些困惑。看来NHibernate 实际上确实从
System.GUID
转换为SQL Server 的uniqueidentifier
(这是有道理的,因为两者都与Microsoft 相关)。然而,我不相信有 Hibernate 的等价物。The Java
UUID
(java.util.UUID
) and the SQL Serveruniqueidentifier
are two different things. You are telling Hibernate to map between the two. I'm surprised Hibernate is able to do anything at all, and not surprised that what it does generate is very strange.As best I know (don't do much work with SQL Server) Hibernate is going to treat the
uniqueidentifier
as a plain old String column. As such, your best bet would probably be to map it a String. You could still have agetUUID()
andsetUUID()
as...Just make sure if you're doing property-based mapping that Hibernate knows the UUID field is a transient field and doesn't try to store both the ID and the UUID.
It's possible that SQL server has some kind of special UUID class you could use in Java that can convert to/from the Java UUID. It's also possible that some new version of Hibernate has come out with support for mapping java.util.UUID to SQL Server's UUID but I don't think either of these possibilities are true.
Edit: After looking into the problem further I can see some of your confusion. It appears that NHibernate DOES in fact convert from
System.GUID
to SQL Server'suniqueidentifier
(makes sense since both are Microsoft-releated). However, I don't believe there is a Hibernate equivalent.我遇到了同样的问题,我通过向列添加
uuid-char
类型来解决它。I had the same problem and I solved it by adding
uuid-char
type to column.