Hibernate(6)关联关系_单向n对1

1.单向 n-1 关联只需从 n 的一端可以访问 1 的一端

2.实体类
n端:Order.java

public class Order {
    private Integer orderId;
    private String orderName;
    //在n端的实体类中有1端的类型的属性
    private Customer customer;
    //省略getter和setter方法
    ...
}

1端:Customer.java

public class Customer {

    private Integer customerId;
    private String customerName;
    //省略getter和setter方法
    ...
}

3.映射文件
n端:Order.hbm.xml

<hibernate-mapping package="com.withXml.manyToone.entity">
    <class name="Order" table="ORDERS">
        <id name="orderId" type="java.lang.Integer">
            <column name="ORDER_ID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDER_NAME" />
        </property>

    <!-- 在n的一端映射n对1关联关系 -->
    <many-to-one name="customer" class="Customer" column="CUSTOMER" cascade="save-update,delete"></many-to-one>

    </class>
</hibernate-mapping>

1:端Customer.hbm.xml

<hibernate-mapping>

    <class name="com.withXml.manyToone.entity.Customer" table="CUSTOMERS">

        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>

        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMER_NAME" />
        </property>

    </class>
</hibernate-mapping>

4.配置文件中添加Mapping元素

<!-- 配置映射文件时,这两种方法只能使用其中之一,同时使用会报错 -->
    <!--使用配置文件时: 加载映射文件,注意使用的是斜杠作为分割符,有文件的后缀名 -->
    <!-- 使用注解时:加载持久化类文件,注意使用的是圆点作为分割符,无文件的后缀名 -->
<mapping resource="com/withXml/manyToone/entity/Customer.hbm.xml"/>
<mapping resource="com/withXml/manyToone/entity/Order.hbm.xml"/>

5.CRUD测试

public class TestManyToOne {


    //通常生产环境中不会定义Transaction对象 和Session对象为成员变量,因为会出现并发的问题,这是单元测试环境
    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    /**
     * 初始化Session
     */
    @Before
    public void init(){
        //1.获取Configuration 对象
        Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
        //2.获取ServiceRegistry 对象
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().
                    applySettings(configuration.getProperties()).
                    buildServiceRegistry();
        //3.获取SessionFactory 对象,并在ServiceRegistry 对象中注册
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        //4.获取Session 对象
        session = sessionFactory.openSession();
        //5.开启session事务
        transaction = session.beginTransaction();
    }

    /**
     * 关闭Session
     */
    @After
    public void destroy(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    /**
     * 执行保存操作时,先保存一的一端的对象,在保存多的一端的对象时,只有三条insert语句
     * 执行保存操作时,先保存多的一端的对象,在保存一的一端的对象时,有三条insert语句和两条update语句,
     *因为在插入多的一端无法确定外键值,所以只能等一的一端插入后,再更新
     */
    @Test
    public void testManyToOneSave(){
        //客户
        Customer customer = new Customer();
        customer.setCustomerName("CC");
        //订单一
        Order order = new Order();
        order.setOrderName("order-3");
        //订单二
        Order order2 = new Order();
        order2.setOrderName("order-4");

        //设定关联关系,从多的一端维护关联关系
        order.setCustomer(customer);
        order2.setCustomer(customer);

        //执行保存操作,先保存一的一端,在保存多的一端,推荐
        session.save(customer);
        session.save(order);
        session.save(order2);

        //先保存多的一端,在保存一的一端,不推荐
//      session.save(order);
//      session.save(order2);
//      session.save(customer);
    }

    /**
     * 测试客户和订单之间的单向多对一的关联关系,查找操作
     * 若查询多的一端的一个对象,则默认情况下,只查询多的一端的对象,而没有查询关联的对象,即一的一端的对象
     *只有需要使用到关联的对象时,才发送相关的SQL语句,这就是Hibernate的懒加载机制
     * 若在加载关联的对象时,把session关了,就会出现懒加载异常
     */
    @Test
    public void testManyToOneGet(){
        Order order = (Order) session.get(Order.class, 1);
        System.out.println("订单名称:" + order.getOrderName());
        String name = order.getCustomer().getCustomerName();
        System.out.println("订单:" + order.getOrderName() + "的客户是:" + name);

    }

    /**
     * 测试修改操作
     */
    @Test
    public void testManyToOneUpdate(){
        Order order = (Order) session.get(Order.class, 1);
        order.getCustomer().setCustomerName("AAA");
    }

    /**
     * 测试删除操作,删除时,不能从关联的一端进行删除,因为在多的一端的外键引用了一的一端
     * 在多对一映射中,无法从1的一端删除,在一对多映射中,可以中1的一端删除记录,
     *同时还会强制把n端的外键也删除
     */
    @Test
    public void testManyToOneDelete(){
        //从一的一端,删除记录失败,因为一的一端外键被引用无法删除
//      Customer customer = (Customer) session.get(Customer.class, 1);
//      session.delete(customer);
        //从多的一端删除记录
        Order order = (Order) session.get(Order.class, 4);
        session.delete(order);
    }

    /**
     * 级联保存
     */
    @Test
    public void testManyToOneCascadeSave(){
        //客户
        Customer customer = new Customer();
        customer.setCustomerName("CC");
        //订单一
        Order order = new Order();
        order.setOrderName("order-3");
        //订单二
        Order order2 = new Order();
        order2.setOrderName("order-4");

        //设定关联关系,从多的一端维护关联关系
        order.setCustomer(customer);
        order2.setCustomer(customer);

        //执行保存操作,先保存一的一端,在保存多的一端,推荐,设置cascade级联属性之后,
        //仅只保存多端即可,从而省略1的一端,反之则不行因为没有一对多的的映射
//      session.save(customer);
        session.save(order);
        session.save(order2);

    }

}

单向n对1
总结:
n端:
①实体类中添加一个1端类型的属性
②映射文件中使用<many-to-one 映射数据库字段

1端:
①普通的javaBean
②映射文件,类属性和数据库字段一一映射即可

原文地址:https://www.cnblogs.com/tengpengfei/p/10453958.html