公司框架使用的是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的一些其它标准。
分享到:
相关推荐
ORM映射与WEB的应用ORM映射与WEB的应用ORM映射与WEB的应用ORM映射与WEB的应用ORM映射与WEB的应用ORM映射与WEB的应用
NULL 博文链接:https://dreamzhong.iteye.com/blog/1205496
Hibernate orm 实现原理 主要讲解了关于hibernate 的一些知识
Myeclipse自动生成Hibernate配置文件及实体类映射ORM配置文件--hibernate方式
Hibernate框架ORM的实现原理.doc
这是一个hibernateORM一对多映射
ORM映射实现的java源码,可以运行。他是ORM映射的彻底的底层实现,真正的ORM映射的原理。
C# ORM映射 开发及原理 公司内部开发的ORM 源码 禁止商业用途,违者必究!
Java-JDBC【之】实现ORM,结果集映射实体类(ResultSet、注解、反射) 1.ORM实现思路 2.@Table、@Column、标识实体类 2.1.创建注解 @Table、@Column 2.2.标识实体类 2.3.数据库表 3.结果集解析,注解加反射填充实体...
hibernate-orm-master
个人的很详细的Hibernate一对一映射配置详解,对初学者有帮助!
一个自己写的ORM映射实例,他是ORM映射的彻底的底层实现,真正的ORM映射的原理
ORM对象关系映射。。ORM对象关系映射。。太详细了。。最全的介绍。
Hibernate ORM 5.3.7.Final User Guide hibernate 5.3.7版本的用户手册,全英文
实现Hibernate框架中一对一,一对多,多对多关系的单向和双向配置总结!
从hibernate官网下载的hibernate-orm-4.3.9的源代码
hibernate-orm-3.2.zip
附光盘 第二张源代码,,后续上传,作者是:李晓军等,后面我会续发其他章节.
Hibernate源码(hibernate-orm-main.zip)Source Code: Hibernate ORM 是一个为应用程序、库和框架提供对象/关系映射 (ORM) 支持的库。 它还提供了 JPA 规范的实现,这是 ORM 的标准 Java 规范。
AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DTO,一般用于ViewModel模式和跨 服务范畴。AutoMapper给用户提供了便捷的配置API,就像使用约定来完成自动映射那样。...