java关联关系,精通Hibernate:映射一对多关联关系(1)

精通Hibernate:映射一对多关联关系(1)

在域模型中,类和类之间最普通的关系就是关联关系。在UML语言中,关联是有方向的。以客户Customer)和订单Order)的关系为例,一个客户可以发出多个订单,而一个订单只能属于一个客户。

从Order到Customer的关联是多对一关联,这意味着每个Order对象都会引用一个Customer对象,因此在Order类中应该定义一个Customer类型的属性,来引用所关联的Customer对象。

从Customer到Order的关联是一对多的关联,这意味着每个Customer对象都会引用一组Order对象,因此在Customer类中应该定义一个集合类型的属性,来引用所有关联的Order对象。

88817c2b945c81bc5a2bbf60692296db.png

一、建立多对一的单向关联关系

如上例中,我们只需在Order类中定义一个customer属性,而在Customer类中无需定义存放Order对象的集合属性。

Order.java

packagemypack;

publicclassOrderimplementsjava.io.Serializable {

privatelongid;

privateString orderNumber;

privateCustomer customer;//定义一个Customer属性

publicOrder() {

}

publicOrder(Customer customer) {

this.customer = customer;

}

publicOrder(String orderNumber, Customer customer) {

this.orderNumber = orderNumber;

this.customer = customer;

}

//省略了id,orderNumber的构造方法

publicCustomer getCustomer() {

returnthis.customer;

}

publicvoidsetCustomer(Customer customer) {

this.customer = customer;

}

}

Customer类的所有属性都是和CUSTOMERS表中的字段一一对应,因此可以直接使用如下的映射代码:

Order类的orderNumber属性和ORDERS表中ORDER_NUMBER字段对应,映射代码和上面类似,此处省去。我们关注的主要地方是,Order类中的customer属性,因为他是Customer类型的,是与ORDERS表的外键CUSTOMER_ID对应的,它的真实值是存在CUSTOMERS表中而ORDERS表存的只是对它的引用,因此customer的映射方法不能如上面一样。

name="customer"

column="CUSTOMER_ID"

class="mypack.Customer"

not-null="true"

lazy="false"

/>

使用方法のBussiness.java演示:

packagemypack;

importorg.hibernate.*;

importorg.hibernate.cfg.Configuration;

importjava.util.*;

publicclassBusinessService{

publicstaticSessionFactory sessionFactory;

static{

try{

// 初始化

Configuration config =newConfiguration();

config.configure();

sessionFactory = config.buildSessionFactory();

}catch(RuntimeException e){e.printStackTrace();throwe;}

}

/*根据参数指定customer的customer_id找出记录*/

publicList findOrdersByCustomer(Customer customer){

Session session = sessionFactory.openSession();

Transaction tx =null;

try{

tx = session.beginTransaction();

List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId())

.list();

//Hibernate执行:select * from ORDERS where CUSTOMER_ID=customer.getId();

tx.commit();

returnorders;

}catch(RuntimeException e) {

if(tx !=null) {

tx.rollback();

}

throwe;

}finally{

session.close();

}

}

/*根据OID找出指定customer_id的记录*/

publicCustomer findCustomer(longcustomer_id){

Session session = sessionFactory.openSession();

Transaction tx =null;

try{

tx = session.beginTransaction();

Customer customer=(Customer)session.get(Customer.class,newLong(customer_id));

tx.commit();

returncustomer;

}catch(RuntimeException e) {

if(tx !=null) {

tx.rollback();

}

throwe;

}finally{

session.close();

}

}

/*

public void saveCustomerAndOrderWithCascade(){

Session session = sessionFactory.openSession();

Transaction tx = null;

try {

tx = session.beginTransaction();

Customer customer=new Customer("Jack");//创建一个Customer持久化对象

//不保存customer对象,这样执行的话会出现异常

Order order1=new Order("Jack_Order001",customer);

Order order2=new Order("Jack_Order002",customer);//创建两个Order对象

session.save(order1);

session.save(order2);

tx.commit();

}catch (RuntimeException e) {

if (tx != null) {

tx.rollback();

}

e.printStackTrace();

} finally {

session.close();

}

}

*/publicvoidsaveCustomerAndOrder(){

Session session = sessionFactory.openSession();

Transaction tx =null;

try{

tx = session.beginTransaction();

Customer customer=newCustomer("Tom");//创建一个Customer持久化对象

session.save(customer);

Order order1=newOrder("Tom_Order001",customer);

Order order2=newOrder("Tom_Order002",customer);//创建两个Order对象

session.save(order1);

session.save(order2);

// 对同一个customerHibernate执行两次插入ORDERS表

tx.commit();

}catch(RuntimeException e) {

if(tx !=null) {

tx.rollback();

}

throwe;

}finally{

session.close();

}

}

publicvoidprintOrders(List orders){

for(Iterator it = orders.iterator(); it.hasNext();) {

Order order=(Order)it.next();

System.out.println("OrderNumber of "+order.getCustomer().getName()+" :"+order.getOrderNumber());

}

}

publicvoidtest(){

saveCustomerAndOrder();

//  saveCustomerAndOrderWithCascade();

Customer customer=findCustomer(1);

List orders=findOrdersByCustomer(customer);

printOrders(orders);

}

publicstaticvoidmain(String args[]){

newBusinessService().test();

sessionFactory.close();

}

}

上述代码中方法 saveCustomerAndOrderWithCascade()如果没有session.save(customer)这一句,

执行时会抛出PropertyValueException异常,主要原因是:

在调用session.save(order1)方法之前,order1和customer对象都是临时的,临时对象是由new创建的,都是没有持久化的对象。假设 session.save(order1)被成功执行,order1会被成功持久化,变成持久化对象,但是Hibernate不会自动持久化order1所关联的customer对象。

在执行session.save(order1)时,插入ORDERS表记录的CUSTOMER_ID字段为null,这违反了数据库完整性约束,即ORDERS表中不允许CUSTOMER_ID为null。

疑问假设ORDERS表中CUSTOMER_ID字段允许为null:

name="customer"

column="CUSTOMER_ID"

class="mypack.Customer"

not-null="false"

lazy="false"

/>

这样执行的话,能够成功的向ORDERS表中插入两条数据;但是当Hibernate自动清理flush)缓存中所有持久化对象时,又会抛出新的异常

org.hibernate.TransientObjectException:object references an unsavedtransientinstance -save thetransientinstance before flushing :mypack.Customer

所谓清理是指Hibernate按照持久化对象的属性变化来同步更新数据库。在清理的时候Hibernate会发现order1和order2都引用临时对象customer,而在ORDERS表中CUSTOMER_ID字段为null,这就意味着内存中持久化对象的属性和数据库中记录不一致。之所以会报错是因为order1中customer属性引用了一个临时对象Customer。

由此可见,Hibernate持久化一个对象时,默认情况下不会自动持久化所关联的其他对象。但是,我们我们希望当Hibernate持久化Order对象时自动持久化所关联的Customer对象,我们可以修改映射文件如下:

name="customer"

column="CUSTOMER_ID"

class="mypack.Customer"

cascade="save-update"

not-null="false"

lazy="false"

/>

当cascade属性为“save-update”,表明保存或更新对象时,会级联保存或更新与它所关联的对象。如上例中,执行saveCustomerAndOrderWithCascade()时,Hibernate会把order1与customer对象一起持久化,此时Hibernate会执行

insert into CUSTOMERS(ID,NAME) values(2,"Jack");

insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) value (3,"Jack_Order001",2);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值