Hibernate复合主键映射
目录:
1. 实现方式一:将复合主键对应的属性与实体其他普通属性放在一起
2. 实现方式二:将主键属性提取到一个主键类中,实体类只需包含主键类的一个引用
hibernate中复合主键的映射方式有两种。
1、基于实体类属性的复合主键
2、基于主键类的复合主键
两种映射方式的区别在于:第一种方式,主键字段和普通字段都在一个实体类中,第二种方式是单独将主键字段提取出来放到一个实体类中。
复合主键映射,主键所在的实体类,要实现Serializable接口,要覆盖hashCode()和equals()方法。
在日常开发中会遇到这样一种情况,数据库中的某张表需要多个字段列才能唯一确定一行记录,这时表需要使用复合主键。面对这样的情况Hibernate为我们提供了两种方式来解决复合主键问题。
方式一:将复合主键对应的属性与实体其他普通属性放在一起
例如实体类People中"id"和"name"属性对应复合主键:
/*实体类,使用复合主键必须实现Serializable接口*/
public class People implements Serializable
{
private static final long serialVersionUID = -4888836126783955019L;
private String id;
private String name;
private int age;
public People()
{
}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
People other = (People) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
}
People.hbm.xml:
按 Ctrl+C 复制代码
按 Ctrl+C 复制代码
Hibernate中使用复合主键时需要注意一些规则:
1. 使用复合主键的实体类必须实现Serializable接口。必须实现Serializable接口的原因很简单,我们查找数据的时候是根据主键查找的。打开Hibernate的帮助文档我们可以找到get与load方法的声明形式如下:
Object load(Class theClass,Serializable id)
Object get(Class theClass,Serializable id)
当我们查找复合主键类的对象时,需要传递主键值给get()或load()方法的id参数,而id参数只能接收一个实现了Serializable接口的对象。而复合主键类的主键不是一个属性可以表示的,所以只能先new出复合主键类的实例(例如:new People()),然后使用主键属性的set方法将主键值赋值给主键属性,然后将整个对象传递给get()或load()方法的id参数,实现主键值的传递,所以复合主键的实体类必须实现Serializable接口。
2. 使用复合主键的实体类必须重写equals和hashCode方法。必须重写equals和hashCode方法也很好理解。这两个方法使用于判断两个对象(两条记录)是否相等的。为什么要判断两个对象是否相等呢?因为数据库中的任意两条记录中的主键值是不能相同的,所以我们在程序中只要确保了两个对象的主键值不同就可以防止主键约束违例的错误出现。也许这里你会奇怪为什么不使用复合主键的实体类不重写这两个方法也没有主键违例的情况出现,这是因为使用单一主键方式,主键值是Hibernate来维护的,它会确保主键不会重复,而复合主键方式,主键值是编程人员自己维护的,所以必须重写equals和hashCode方法用于判断两个对象的主键是否相同。
3. 重写的equals和hashCode方法,只与主键属性有关,普通属性不要影响这两个方法进行判断。这个原因很简单,主键才能决定一条记录,其他属性不能决定一条记录。
保存测试:
public class Client
{
public static void main(String[] args)
{
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try
{
tx = session.beginTransaction();
People people = new People();
/*主键值由我们自己维护*/
people.setId("123456");
people.setName("zhangsan");
people.setAge(40);
session.save(people);
tx.commit();
}
catch (Exception e)
{
if(tx != null)
{
tx.rollback();
}
e.printStackTrace();
}
finally
{
session.close();
}
}
}
看看数据库:
数据被正确的插入到数据库中了。
读取数据测试:
public class Client
{
public static void main(String[] args)
{
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try
{
tx = session.beginTransaction();
/*查询复合主键对象,需要先构建主键*/
People peoplePrimaryKey = new People();
peoplePrimaryKey.setId("123456");
peoplePrimaryKey.setName("zhangsan");
/*然后将构建的主键值传入get方法中获取对应的People对象*/
People people = (People)session.get(People.class, peoplePrimaryKey);
System.out.println("people age is:"+people.getAge());
tx.commit();
}
catch (Exception e)
{
if(tx != null)
{
tx.rollback();
}
e.printStackTrace();
}
finally
{
session.close();
}
}
}
控制台输出:
可以看到数据成功的取出了。
方式二:将主键属性提取到一个主键类中,实体类只需包含主键类的一个引用。
主键类:
/*必须实现Serializable接口*/
public class PeoplePrimaryKey implements Serializable
{
private static final long serialVersionUID = -1190986010439330142L;
/*复合主键值*/
private String id;
private String name;
public PeoplePrimaryKey()
{
}
/*复合主键值的get和set方法*/
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PeoplePrimaryKey other = (PeoplePrimaryKey) obj;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (name == null)
{
if (other.name != null)
return false;
}
else if (!name.equals(other.name))
return false;
return true;
}
}
实体类:
public class People
{
/*持有主键类的一个引用,使用该引用作为这个类的OID*/
private PeoplePrimaryKey peoplePrimaryKey;
private int age;
public People()
{
}
public PeoplePrimaryKey getPeoplePrimaryKey()
{
return peoplePrimaryKey;
}
public void setPeoplePrimaryKey(PeoplePrimaryKey peoplePrimaryKey)
{
this.peoplePrimaryKey = peoplePrimaryKey;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
People.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="com.suxiaolei.hibernate.pojos.People" table="people">
<!-- 复合主键使用composite-id标签 -->
<!--
name - 指定了复合主键对应哪一个属性
class - 指定了复合主键属性的类型
-->
<composite-id name="peoplePrimaryKey" class="com.suxiaolei.hibernate.pojos.PeoplePrimaryKey">
<!-- key-property指定了复合主键由哪些属性组成 -->
<key-property name="id" column="id" type="string"></key-property>
<key-property name="name" column="name" type="string"></key-property>
</composite-id>
<property name="age" column="age" type="integer"></property>
</class>
</hibernate-mapping>
场景测试与方式一大同小异这里不再举例了。主键类为什么实现Serializable接口和为什么重写equals和hashCode方法上面已经解释的很清楚了。
分享到:
相关推荐
这时,弹出一个编辑实体类窗体,在这里可以对即将要生成的实体类信息进行检查并修改信息。 11.修改完毕后,点击生成。完毕后提示生成成功! *备注:程序中每一步都有相对应的必要检测,当用户选择不符合必须选择或...
mybatis自动导入实体类和xml工具包 自动生成实体类和xml 配置的过程在我的博文里有
java 从数据库表反射出实体类,自动生成实体类
为了解决这个问题,开发了这个Java实体类字段生成工具类。 2、该工具类可以将数据库表列字段转化为对应的Java实体类字段。生成的实体类字段格式清晰易读,且符合Java命名规范。通过使用该工具类,可以大大提高开发...
因为.net core不能一键生成EF数据结构,所以做了个数据库实体类代码生成器,一键生成数据库所有表的实体类,代码可以参考,特殊需求可以自己改
可以自动于sql数据库连接,分析数据库表,并自动生成实体类,减少写实体类的时间
sqlsugar怎么利用t4模板生成实体类;以及sqlsugar简单的增删改查。自己整理的,方便以后查找
sql server数据库表生成实体类生成工具
Mybatis自动生成实体类,XML文件
实体类生成器实体类生成器实体类生成器实体类生成器
配置好数据库连接字符串和输出路径,自动把MySQL数据表生成相应的Java实体类。附上数据库。来源是参考别人的代码,有添加了自动获取表名的功能,不需要手动写表名,非常方便。
可以通过SQLserver生成或者批量导出实体类,非常方便 C#根据SQLserver生成实体类 工具-源码
用一个根据数据库表自动生成实体类代码的案例讲解了代码生成器的核心思路,相关博客地址:https://blog.csdn.net/qq_31142553/article/details/93673384。
自动生成hibernate映射文件和实体类
实体类&SQL生成工具\可以快速生成vb、c#、java实体类
实体类生成工具 实体类生成工具 实体类生成工具 实体类生成工具 实体类生成工具 实体类生成工具 实体类生成工具 实体类生成工具
根据网上资料做的实体类生成工具源码,个人习惯,自己喜欢就好。 主要功能: 根据MSSQL数据表生成实体类部分代码,主要代码如下所示. /// /// 单据ID /// public int DocEntry { get; set; }
自动生成所有sql数据库用户表的所有实体类.... .net代码
此代码生成器可以自动的生成实体类。此代码生辰器可以关联数据库中的表来生成相应的实体类
超好用的实体类生成工具,比其他实体类生成工具都全面,支持检索表名,支持批量生成等功能。