别让Hibernate偷走了你的标识符 - 编程入门网
son();
Set set = new HashSet();
set.add(p);
System.out.println(set.contains(p));
p.setId(new Long(5));
System.out.println(set.contains(p));
打印结果: true false 对set.contains(p)的第2次调用返回了false是因为Set再也找不到p了。用书面化的语言讲,Set丢失了这个对象!这是因为当对象在Set中时,我们改变了hashCode()的返回值。 别让Hibernate偷走了你的标识符(3)时间:2011-01-04当你想要创建一个将其它域对象保存在Set,Map或是List里面的域对象时,这是一个问题。为了解决这个问题,你必须为你的所有对象提供一种equals()和hashCode()的实现,这种实现能够保证在它们在对象保存前后正确工作并且当对象在内存中时(返回值)不会改变。Hibernate参考文档提供了以下的建议: “不要使用数据库标识符来实现等价的判断,而应该使用商业键值(business key),一种唯一的,通常不改变的属性的结合体。当一个buk不可序列化对象(transient object)被持久化的时候,数据库标识符会发生改变。当一个不可序列化实例(常常和detached instances在一起)被包含在一个Set里面时,哈希值的改变会破坏Set的从属关系。商业键值的属性并不要求和数据库主键一样稳定,你只要保证当对象在某个Set中时它们的稳定性。 “我们推荐判断商业键值的等价性来实现equals()和hashCode()两个方法。这意味着equals()方法只比较能够区分现实世界中的实例的商业键值(某个候选码)的属性。“(Hibernate 参考文档 v. 3.1.1). 换句话说,equals()和hashCode()使用商业键值进行处理,而对象使用Hibernate生成的键值作为id值。这要求对于每个对象有一个相关的不会改变的商业键值。可是,并不是每个对象类型都有这样的一种键,这时候你可能会尝试使用会改变但不时常改变的字段。这和商业键值不必和数据库主键一样稳定的思想相吻合。当对象在Collection中时候如果这种键不改变,那它们似乎就“足够好”了。这是一种危险的主张,这意味着你的应用程序可能不会崩溃,但是前提是没有人在特定的情况下更新了特定的字段。所以,应当有一种更好的解决方案,而它确实也存在。 试图创建和维护在对象和数据库行两者间有着分离的定义的标识符是目前为止讨论的所有问题的根源。如果我们统一所有标识符的形式,这些问题都将不复存在。也就时说,作为以数据库为中心和以对象为中心的标识符的替代品,我们应该创建一种通用的,特定于实体的ID来代表数据实体,这种ID应该在数据第一次输入的时候产生。无论一个唯一数据实体是保存在数据库,是作为对象驻留在内存,还时存贮在其它格式的介质中,这个通用ID都应该可以识别它。通过使用数据实体第一次创建时指派的ID,我们可以安全的回到我们对equals()和hashCode()的原始定义。它们只是简单地使用了这个id:
|
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |