`
spiniper
  • 浏览: 5700 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

关于Hibernate ORM映射实体通用hashCode与equals方法的实现

阅读更多
公司框架使用的是spring mvc +spring+hibernate 各个版本都很新,hibernate主要使用的是注解映射,说实话,对开发上来说,比xml配置文件要方便得多,而且注解也支持继承,因此父类的实现可以大大降低工作量了,想以前hibernate还是配置文件的年代的时候,很多表的字段是重复固定的,如ID,创建人,创建时间等等,那个时候虽然java层面的实体可以基类,然后通过继承来减轻工作量,可是配置文件却要每个xml都复制一道(也许有方便的方式,可惜我没找到),现在有了注解,就不用这样恶心的复制了。
其实前面废话这么多,也就做个铺垫,因为这次主要说说的是hashCode与equals方法,hashCode方法很多开发人员也许不会有多少感性的认知,但是更多的人对equals方法应该很熟悉才是,hashCode方法其实与其一样,也是用于对象比较的,且其更实用(就是获得其值比较大小,很多jdk内置的一些工具的比较与排序都是使用其来完成的,因此它是一个极其重要的方法)。对于java的一些开发规范来说,对于一个java类的开发,必须实现hashCode与equals来重实现对象比较逻辑。
这次主要任务就是要实现一个hibernate映射父类的hashCode方法与equals方法,因为我并不希望每一个orm映射类都要去实现一个这样的方法,其一这没有必要,其二也为了大大减轻一些工作量,最终目的也是能够实现一个能够适用于jdk一些内置工具的orm映射体系,不会让orm对象在使用HashSet或者Map之类的工具时,让orm 对象表得奇怪。
对于表的映射orm的比较其实逻辑上多很简单,我们约定每个表的内置主键名都是id字段,因此同一个orm映射对象的比较,只要比较id就可以了,id不同的话,那么表示此对象不同,否则就相同,排序也根据其来排序。
初步的实现为下
	public int hashCode() {
		return id.intValue();
	}

	public boolean equals(Object obj) {
		
		return this.id.longValue()==entity.id.longValue();
	}

我们的id是java.lang.Long类型的,因此转换成hashCode需要intValue()一下。
但是我们实现的逻辑在父类中,也就是说,这两个方法会被其继承的子类所使用,而不同子类映射不同的表,而不同的表中所生成的主键id是完全可以相同的,在这里比对ID之前,必须比对类型,这样就可以确保对象的比对是在同一个类型下比较的,于是在之前加入如下代码:
	public int hashCode() {
                int id=this.id==null?0:this.id.intValue();
		return id^this.getClass().getName().hashCode();
	}

	public boolean equals(Object obj) {
		if(!this.getClass().getName().equals(obj.getClass().getName())){
			return false;
		}
		return this.id.longValue()==entity.id.longValue();
	}

这里为什么不直接比较Class,而要比较Class对象的name属性,因为Class没有自己实现hashCode方法与equals方法,且某个类的Class对象在虚拟机中也不一定会是单例的,因为同样的类可能由不同的类装载器完成装载,这样在虚拟机中就会存在两个完全相同的类的Class对象,而且这两个对象会在一些时候碰头,最典型的例子就是你用oracle驱动包中的Timestamp的class模板去比较一个由jdbc装载的一个Timestamp对象的getClass的模板,你会发现它们的全限定名完全相同,但是equals却返回false。因此此处必须比较name,因为name转换为String,比较是不会出现歧义的。
在使用一段时间后,又发现问题,比较类模板也是不行的,这是因为hibernate的延迟加载机制的缘故,因为延迟加载改变了原始的类模板,使用了重新生成的代理类,这时,我们自己生产的对象与hibernate装载的对象,我们自以为是相同的,但实际却不同,因为我们使用的类模板是原始类模板,而hibernate装载的却是修改过的代理类模板,如此一来,简单的类模板比对则无用了,后来经过我冥思苦想,终于找到一个替代性的办法,也许这个方式并不成熟,因为我们使用的是注解,因此我打算利用注解的@Table的name属性来完成比对(我们规定每个orm映射都要指定表名,因此这种方式对我们的系统来说可行的),如今代码如下,这是先行版的完整代码:
	public int hashCode() {
		String tableName=this.tableName();
		int id=this.id==null?0:this.id.intValue();
		if(StringUtils.isNotBlank(tableName)){
			return id^tableName.hashCode();
		}else{
			return id^this.getClass().hashCode();
		}
		
	}

	public boolean equals(Object obj) {
		if(obj==null){
			return false;
		}
		if(!(obj instanceof IdEntity)){
			return false;
		}
		IdEntity entity=(IdEntity) obj;
		if(this.id==null||entity.id==null){
			return false;
		}
		boolean typecheck=false;
		if(StringUtils.isNotBlank(this.tableName())){
			this.tableName().equals(entity.tableName());
		}else{
			typecheck=this.entityName().equals(entity.entityName());
		}
		return (this.id.longValue()==entity.id.longValue())&&typecheck;
	}

里面实现了一些equals的一些其它标准。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics