6、Hibernate的映射关系
映射关系 | XML(在<class/>配置) | Annoation |
1 :1主键 | 参考类StuIdCard.hbm.xml <id name="id"> <generator class="foreign"></generator> </id> <one-to-one name="student" class="Student" constrained="true"/> 主类(被参考表) Student.hbm.xml <one-to-one name="stuIdCard" class="StuIdCard" property-ref=”student”/> | @OneToOne @PrimaryKeyJoinColumn 双向: 实体类之间持有对方的引用 |
1 :1 外键 | Employee.hbm.xml <many-to-one name="person" class="Person" column="PERSON_ID"unique="true"/> Person.hbm.xml <one-to-one name="employee" class="Employee" property-ref="person"/> | @OneToOne 双向:@OneToOne(mappedBy=”在主要的类中定义”) |
1 :n n : 1 多一方 设置外键 少一方写 | Group.hbm.xml <set name="users" cascade=”all” table=”” > //与user做关联 <key column="groupId"></key> //多的一方设置 <one-to-many class="com.bjsxt.hibernate.User"/> </set> User.hbm.xml(双向) <many-to-one name="group" class=”Group” column="groupId" /> | 单向 User @ManyToOne
@OneToMany @JoinColumn(name="groupId") //getUsers()前将在User表添加groupId外键字段,这样就会在多的一方设置 双向 Group @OneToMany(mappedBy=”group”) Public list getUser |
n : m | Teacher.hbm.xml <set name="students" table="t_s"> //持有对方的引用 <key column="teacher_id"></key> //自己 <many-to-many class=" Student" column="student_id"/> </set> Student.hbm.xml <set name="teachers" table="t_s"> <key column="student_id"></key> <many-to-many class=" Teacher" column="teacher_id"/> </set> | Teacher @ManyToMany @JoinTable(name="t_s", joinColumns={@JoinColumn(name="teacher_id")}, inverseJoinColumns={@JoinColumn(name="student_id")} ) 双向: Student @ManyToMany(mappedBy="students") |
组件映射 | <component name=”wife” class=”Wife”> <property name=” wifeName” /> </component> | 在主类getWife()上定义 @Embedded 被嵌入类不用写@Entity |
联合主键 | <compsite-id name=”对象”, class=”类”> <key-property name=”key1” /> <key-property name=”key2”/> </compsite-id> | 在主类getWife()上定义 @OneToOne @JoinColumns( {@JoinColumn(name="wifeId",referencedColumnName="id"), @JoinColumn(name="wifeName",referencedColumnName="name") } ) |
没有建外键关联是一件很危险的事,这时候会产生ID不一致的事,参考类ID要参考主类的ID l class (可选 -默认是通过反射得到的属性类型):被关联的类的名字。 |
l constrained(约束) (可选)表明该类对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。设置外键关联 |
l property-ref: (可选)由对方那里设置 |
集合映射(在getUser()上设置)
@MapKey(name=”key”)
for (Iterator <Map.Entry<Integer, User>> iter = g.getUser().entrySet().iterator(); iter.hasNext();) {
Map.Entry<Integer, User> element = (Map.Entry<Integer, User>) iter.next();
}
for(Map.Entry<Integer, User> entry : g.getUser().entrySet()) {
System.out.println(entry.getValue().getName());
}
@OrderBy(”user”)
关联更新
fetch 和 lazy 主要是用来级联查询的, 而 cascade 和 inverse 主要是用来级联插入和修改的 fetch参数指定了关联对象抓取的方式是select查询还是join查询,select方式时先查询返回要查询的主体对象(列表),再根据关联外键 id,每一个对象发一个select查询,获取关联的对象,形成n+1次查 询;而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。
如果你的关联对象是延迟加载的,它当然不会去查询关联对象。另外,在hql查询中配置文件中设置的join方式是不起作用的(而在所有其他查询方式如get、criteria或再关联获取等等都是有效的),会使用 select方式,除非你在hql中指定join fetch某个关联对象。Fetch策略用于定义 get/load一个对象时,如何获取非lazy的对象/集合。这些参数在Query中无效。
当使用Hibernate中的one-to-many、many-to one、many-to-many关系映射的时候,一个对象中会包含一个或多个Set来关联其他的对象。例如:user-groups,当程序取user 对象时,如果一个用户有多个自定义组,那么程序将把组的信息也读取出来,在log中可以看到两个sql的输出。但是在页面的显示上,也许并不需要显示这个用户相关组的信息,这样系统的消耗就白白浪费了,于是hibernate提供了lazy(延迟加载)的方法来避免这一情况的发生,我们只需要在 user.hbm.xml中设置lazy=true(默认),就能实现延迟加载。
代码:<set name="groupses" table="usergroups" catalog="many" cascade="save-update" lazy="true">
<key>
<column name="userid" length="32" not-null="true" /> //自己
</key>
<many-to-many entity-name="com.example.model.Groups">
<column name="groupid" length="32" not-null="true" />
</many-to-many>
</set>
继承映射
每个类一张表(Andriod的hibernate_0300)
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable {
}
这种策略支持双向的一对多关联. 这里不支持IDENTITY生成器策略,因为id必须在多个表间共享.一旦使用这种策略就意味着你不能使用 AUTO 生成器和IDENTITY生成器. 这时候可以用@TableGenerator ID生成策略
<class name="com.bjsxt.hibernate.Animal" abstract="true">
<id name="id">
<generator class="assigned"/>
</id>
<property name="name"/>
<property name="sex"/>
<union-subclass name="com.bjsxt.hibernate.Pig" table="t_pig">
<property name="weight"/>
</union-subclass>
<union-subclass name="com.bjsxt.hibernate.Bird" table="t_bird">
<property name="height"/>
</union-subclass>
</class>
每个子类对应一张表,子类只写特有部分,但子类所对应的数据库表信息是完备的,即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,joined-subclass定义的子类的表,只包含子类特有属性映射的字段)
父类跟子类一张表
整个继承层次结构中的父类和子类的所有属性都映射到同一个表中, 他们的实例通过一个辨别符(discriminator)列来区分.:
//父类
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="planetype",
discriminatorType=DiscriminatorType.STRING
)
//子类
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }
<class name="Payment" table="PAYMENT">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="PAYMENT_TYPE" type="string"/>
<property name="amount" column="AMOUNT"/>
...
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
<property name="creditCardType" column="CCTYPE"/>
...
</subclass>
<subclass name="CashPayment" discriminator-value="CASH">
...
</subclass>
…
</class>
使用这种映射方式需要注意的是它通过<discriminator>标签(<discriminator column="employee_type"type="string"/>)增加一个字段(这里是employee_type字段)来标示某个记录是属于哪个实体对象的。通过<subclass>标记中的discriminator-value属性来定义哪个值代表哪个子类的持久化对象。.
链接的子类
当每个子类映射到一个表时, @PrimaryKeyJoinColumn 和@PrimaryKeyJoinColumns 注解定义了每个子类表关联到父类表的主键:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Boat implements Serializable { ... }
@Entity
public class Ferry extends Boat { ... }
@Entity
@PrimaryKeyJoinColumn(name="BOAT_ID")
public class AmericaCupClass extends Boat { ... }
以上所有实体都使用了JOINED策略, Ferry表和Boat表使用同名的主键. 而AmericaCupClass表和Boat表使用了条件Boat.id = AmericaCupClass.BOAT_ID进行关联. 主表包含共同的字段,子表就写特有的属性字段。此时子类的主键表参考主表的主键。
适用于不使用多态的情况下
·跟每个类建一张表的区别:
① 每个类一张表的映射策略所建立的表示独立的,每个表都包括子类所自定义 的属性和由父类锁继承的属性的映射字段。
② 只为具体类建表,子类所对应的表只包括子类所定义的属性,而子类所对应的 表与父类所对应的表是通过外键来进行关联的,即当持久化一个子类时,需要在父类的表和子类的表各增加一条记录,这两个记录通过外键来关联。
·好处:父类所定义的属性就在父类的表中进行映射,而子类所定义的属性就在子类的表中进行映射。避免了子类所定义的表中仍然需要定义父类属性的映射字段。
<class name="Employee" table="employee3">
<id name="oid" column="oid" >
<generator class="native">
</generator>
</id>
<property name="name" />
<joined-subclass name="HourlyEmployee" table="hourly2">
<key column="oid"></key>
<property name="rate"></property>
<many-to-one name="Company" column="companyid"
cascade="save-update">
</many-to-one>
</joined-subclass>
<joined-subclass name="SalariedEmployee" table="salaried2">
<key column="oid"></key>
<property name="salary"></property>
<many-to-one name="Company" column="companyid"
cascade="save-update">
</many-to-one>
</joined-subclass>
</class>
先表还是先类
实际工作当中先建表:对表进行优化,比如说建索引,建视图,建各种各样的优化