dljd_(067-070)_hibernate_关联关系映射_自关联

一、自关联

  是指,自己即充当一方,又充当多方,是1:n的变型。例如,对于新闻栏目NewsColumn,可以充当一方,即父栏目,也可以充当多方,即子栏目。而这些反映到数据库表中,只有一张表,这张表中具有一个外键,用于表示该栏目的父栏目。一级栏目的外键值为null,而子栏目则具有外键值。还有很多中这种例子,比如企业的员工表。每个员工都有自己的上级(除老板、老板的上级为null)、而自己的上级又在这张员工表中。

二、程序示例(新闻条目类)

  新闻条目分为:父条目和子条目。

package edu.aeon.beans;

import java.util.HashSet;
import java.util.Set;

/**
 * [说明]:新闻条目类
 * @author aeon
 *
 */
public class NewsLabel {
    /**新闻条目id*/
    private Integer newsId;
    /**新闻条目标题*/
    private String newsTitle;
    /**新闻条目内容*/
    private String newsContext;
    /**新闻父条目*/
    private NewsLabel parentNewsLabel;
    /**新闻子条目*/
    private Set<NewsLabel> childNewsLabels;
    public NewsLabel() {
        super();
        childNewsLabels=new HashSet<NewsLabel>();
    }
    public NewsLabel(String newsTitle, String newsContext) {
        this();
        this.newsTitle = newsTitle;
        this.newsContext = newsContext;
    }

    public Integer getNewsId() {
        return newsId;
    }
    public void setNewsId(Integer newsId) {
        this.newsId = newsId;
    }
    public String getNewsTitle() {
        return newsTitle;
    }
    public void setNewsTitle(String newsTitle) {
        this.newsTitle = newsTitle;
    }
    public String getNewsContext() {
        return newsContext;
    }
    public void setNewsContext(String newsContext) {
        this.newsContext = newsContext;
    }
    public NewsLabel getParentNewsLabel() {
        return parentNewsLabel;
    }
    public void setParentNewsLabel(NewsLabel parentNewsLabel) {
        this.parentNewsLabel = parentNewsLabel;
    }
    public Set<NewsLabel> getChildNewsLabels() {
        return childNewsLabels;
    }
    public void setChildNewsLabels(Set<NewsLabel> childNewsLabels) {
        this.childNewsLabels = childNewsLabels;
    }
    @Override
    public String toString() {
        return "NewsLabel [newId=" + newsId + ", newsTitle=" + newsTitle + ", newsContext=" + newsContext
                + ", childNewsLabels=" + childNewsLabels + "]";
    }
}
NewsLabel.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="edu.aeon.beans">
    <class name="NewsLabel">
        <id name="newsId">
            <column name="newsId" sql-type="int(3)"/>
            <generator class="native"/>
        </id>
        <property name="newsTitle">
            <column name="newsTitle" sql-type="varchar(200)"/>
        </property>
        <property name="newsContext">
            <column name="newsContext" sql-type="varchar(1000)"/>
        </property>
        <!-- 关联属性的映射配置 -->
        <!-- name:关联属性的属性名 -->
        <set name="childNewsLabels"  cascade="save-update">
            <!-- 关联的外键 -->
            <key column="pid" />
            <!-- 关联到那个类 -->
            <one-to-many class="NewsLabel" />
        </set>
        <many-to-one name="parentNewsLabel" cascade="save-update" class="NewsLabel" column="pid" />
    </class>
</hibernate-mapping>

然后将NewsLabel.hbm.xml注册到hibernate的主配置文件里面:

  

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 配置数据库的四要素 -->
        <property name="hibernate.connection.driver">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_test</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!-- 配置数据库方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- 配置数据库连接池 -->
        <!-- <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property> -->
        <!-- 注册当前session上下文 -->
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- 自动建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 显示sql -->
        <property name="hibernate.show_sql">true</property>
        <!-- 格式化sql -->
        <property name="hibernate.format_sql">true</property>
        <mapping resource="edu/aeon/beans/NewsLabel.hbm.xml"/>
    </session-factory>
</hibernate-configuration>    

单方(父条目)维护时的测试类

package edu.aeon.hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import edu.aeon.aeonutils.hibernate.getsessionutil.GetSessionUtil;
import edu.aeon.beans.NewsLabel;

/**
 * [说明]:测试自关联
 * @author aeon
 *
 */
public class HibernateTest {
    /**
     * 自关联
     */
    @Test
    public  void testOne2Many(){
        Session session=null;
        Transaction transaction=null;
        try {
            session = GetSessionUtil.getSession();
            System.out.println(session);
            transaction = session.getTransaction();
            transaction.begin();
            NewsLabel child1=new NewsLabel("乒乓球", "乒乓球乒乓球乒乓球乒乓球乒乓球乒乓球");
            NewsLabel child2=new NewsLabel("篮球", "篮球篮球篮球篮球篮球篮球篮球篮球篮球篮球篮球");
            NewsLabel parent=new NewsLabel("体育", "这是体育!");
            //有parent去维护
            parent.getChildNewsLabels().add(child1);
            parent.getChildNewsLabels().add(child2);
            session.save(parent);//由谁维护保存谁
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        }
    }
}

测试结果控制台:

  

Hibernate: 
    
    create table NewsLabel (
        newsId int(3) not null auto_increment,
        newsTitle varchar(200),
        newsContext varchar(1000),
        pid integer,
        primary key (newsId)
    )
Hibernate: 
    
    alter table NewsLabel 
        add constraint FKnxywagk83uy0fknne0t4nf59w 
        foreign key (pid) 
        references NewsLabel (newsId)
ThreadLocalSessionContext.TransactionProtectionWrapper[SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
Hibernate: 
    insert 
    into
        NewsLabel
        (newsTitle, newsContext, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        NewsLabel
        (newsTitle, newsContext, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        NewsLabel
        (newsTitle, newsContext, pid) 
    values
        (?, ?, ?)
Hibernate: 
    update
        NewsLabel 
    set
        pid=? 
    where
        newsId=?
Hibernate: 
    update
        NewsLabel 
    set
        pid=? 
    where
        newsId=?

测试结果截图:

  

数据库数据信息截图如下:
  

  

  

 

 由多方(子条目)维护关联关系时的测试类:

 

package edu.aeon.hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import edu.aeon.aeonutils.hibernate.getsessionutil.GetSessionUtil;
import edu.aeon.beans.NewsLabel;

/**
 * [说明]:测试自关联
 * @author aeon
 *
 */
public class HibernateTest {
    /**
     * 自关联
     */
    @Test
    public  void testOne2Many(){
        Session session=null;
        Transaction transaction=null;
        try {
            session = GetSessionUtil.getSession();
            System.out.println(session);
            transaction = session.getTransaction();
            transaction.begin();
            NewsLabel parent=new NewsLabel("体育", "这是体育!");
            NewsLabel child=new NewsLabel("乒乓球", "乒乓球乒乓球乒乓球乒乓球乒乓球乒乓球");
            //有child去维护
            child.setParentNewsLabel(parent);
            session.save(child);//由谁维护保存谁
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            e.printStackTrace();
        }
    }
}

 测试结果:

  

Hibernate: 
    
    create table NewsLabel (
        newsId int(3) not null auto_increment,
        newsTitle varchar(200),
        newsContext varchar(1000),
        pid integer,
        primary key (newsId)
    )
Hibernate: 
    
    alter table NewsLabel 
        add constraint FKnxywagk83uy0fknne0t4nf59w 
        foreign key (pid) 
        references NewsLabel (newsId)
ThreadLocalSessionContext.TransactionProtectionWrapper[SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
Hibernate: 
    insert 
    into
        NewsLabel
        (newsTitle, newsContext, pid) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        NewsLabel
        (newsTitle, newsContext, pid) 
    values
        (?, ?, ?)

测试结果截图:

  

此时我们去看下数据库中的数据信息:

  

  

  

  这样设计的表如何去区分父条目和子条目呢?满足pid is null的条目均为父条目,pid上有主键值指向的是子条目、且该主键值值为它的父条目的id

 

 

 

 

 

转载于:https://www.cnblogs.com/aeon/p/10119841.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值