相對的一對多和多對一,hibernate很傷神

導讀

最近公司在作這樣的一個業務,由我來設計數據庫,其中有有一個需求,根據原型圖設計數據庫,這也是我第一次獨立設計數據庫,因涉及公司的機密,只能展現部分原型圖:前端

一、如圖是項目的原型圖,每一個項目都是一條記錄,於是,這能夠設計成獨立的項目表
項目原型圖算法

二、當點擊紅框中的「人員」,就會出現一個彈框,彈框如圖所示。spring

項目人員原型圖

這是項目人員,天然關聯對應項目。不一樣的項目可能有不一樣的人員。於是,這能夠設計成一張項目人員表。表中的字段確定有「人員類型」,好比業務員,業務部經理等。外鍵天然是項目主鍵。一個項目可能會有多條記錄,好比說業務員一條記錄,業務部經理一條記錄等。因此,對於項目而言,這是一對多的關係,是什麼意思呢?一個項目在項目人員表有多條記錄;但對於項目人員來講,這是多對一的關係,多條項目人員的記錄對着一個項目。如圖所示:數據庫

項目對於項目人員表是一對多的關係

生成數據表結構是有Java代碼生成的,於是,代碼以下:編程

/**
 * Created By zby on 15:00 2018/12/25
 * 項目人員
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "zq_project_person")
public class ProjectPerson extends BaseObj {

    /**
     * 人員類型
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "person_type")
    private PersonTypeEnum personType;

    /**
     * 人員的ids,存儲人員的編號
     */
    @Column(name = "ids")
    private String ids;

    /**
     * 選擇時間
     */
    @Column(name = "op_time")
    private Date opTime;

    /**
     * 項目
     */
    @ManyToOne
    @JoinColumn(name = "project_id")
    private Project project;

}

人員類型是枚舉,代碼以下:數組

/**
 * Created By zby on 9:43 2018/12/27
 */
public enum PersonTypeEnum implements TitleEnum {
    PERSON_TYPE_SALESMAN("業務員"),
    PERSON_TYPE_SALESMAN_MANAGER("業務部經理"),
    PERSON_TYPE_DESIGNER("設計師"),
    PERSON_TYPE_DESIGNER_MANAGER("設計部經理"),
    PERSON_TYPE_PROJECT_SUPERVISION("工程監理"),
    PERSON_TYPE_ENGINEERING_MANAGER("工程部經理");

    。。。

一對多和多對一

一和多的概念

經過以上的分析,咱們知道一對多和多對一的關係。這個「一」「多」。究竟是什麼是 「一」,什麼又是「多」呢?在實際的項目中,咱們多問幾個爲何,成長也會特別的快。不要怕問,也許,人家可能沒時間回答你,或許,人家懼怕把你教會了。這樣,也要問,不問就永遠不知道。ide

「一」針對「一個點」來講,就像是spring中的aop(Aspect Oriented Programming)編程同樣。spring框自己就是以算法驅動爲開發,但咱們在使用它時,通常是以業務驅動爲開發的。既然是業務處理,天然涉及到業務的諸多流程,好比,專門將JVM中的瞬時態的對象轉化爲數據庫的持久態的字段值、或將數據庫的持久態的字段值轉化爲瞬時態的Java對象的dao(data access object)層;專門處理數據庫事務相關的事務層(service層);專門處理接受前端數據和返回前端數據的控制層(controller層)。ui

咱們單單隻考慮其中的一個業務流程,即數據庫的事務層(service層)。這就是一個點,也就是aop須要考慮的一個點。aop的配置文件以下所示:spa

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"
       default-lazy-init="true">

    <!-- =================================================================== -->
    <!-- AOP: Configuration and Aspects    @TODO:事務縮小範圍到 固定的 名字                                  -->
      <!-- 採用 ant風格的編寫方式, 一個 * 表示至少有0個字母,兩個 ** 表示至少有0個目錄                        -->
    <!-- =================================================================== -->
    <aop:config>
        <aop:advisor id="managerTxOne" advice-ref="txAdvice" pointcut="execution(* *..service.*Service.*(..))"
                     order="0"/>
    </aop:config>

    <tx:annotation-driven/>

    <!-- 開啓AOP監聽 只對當前配置文件有效 -->
    <aop:aspectj-autoproxy expose-proxy="true"/>

    <!-- 配置各個方法的權限,以get list search 開頭的都是隻讀權限 -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <!--得到單個對象-->
            <tx:method name="get*" read-only="true"/>
            <!--列表對象-->
            <tx:method name="list*" read-only="true"/>
            <!--搜索分頁對象-->
            <tx:method name="search*" read-only="true"/>

            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    
</beans>

咱們注意上面的<aop:config> 。。。</aop:config>這段代碼,其實就是配置的設置這個點。這個是處理全部以service結尾的。設計

於是,再說說咱們數據的庫的 「一」,這是針對一條記錄來講的,好比上文說到的項目表中有不少項目,咱們單單舉出來編號爲167的項目,那麼,這就是 「一」「多」咱們針對的是當前數據表中涉及到外鍵字段的記錄的條數。好比在項目人員表中,外鍵名爲project_id的項目編號等於167的有不少條記錄。那麼,這就是「多」


一對多和多對一的理論示例

因此,一和多之間,並不是絕對的關係,只是相對來講。就像咱們初中學過的運動間的相對關係。什麼是靜止的,什麼是運動的?咱們坐在車箱裏,相對於窗外的行道樹,咱們是運動的。相對於車子,咱們就是靜止的。因此,也有句話,叫作日行不動八萬裏。萬物就是這樣,沒有絕對的關係。於是,在實際的項目中,咱們遇到了太多的一對多(多對一)的關係,好比:

  1. 項目和項目人員就是一個典型的一對多和多對一的關係。由於上文提到了,就再也不贅述。
  2. 項目和項目階段也是一對多和多對一的關係。一個項目從執行到竣工,確定有不少的階段,每一個階段的執行時間、階段名稱、涉及到的人等。於是,這也是一對多的關係。因此,在項目階段表中相同項目編號的記錄至少零條。
  3. 評論表和用戶、文章也是一對多和多對一的關係。好比我在思否寫了篇文章,當其餘用戶登陸了,假設評論個人文章,一個用戶能夠評論屢次一篇文章,一個用戶也能夠評論個人多篇文章。因此,在評論表中,一個用戶的記錄至少零條,一個用戶的文章的記錄數至少零條。
  4. 同一張表中也能夠存在一對多的關係。如文章類型這張表,文章類型確定有父類型。在這張表中,父類型至少有零條記錄數。如欄目,欄目確定有父類型,父欄目下面有子欄目,父欄目的記錄至少有零條。
  5. 根據4所說的,一個文章類型下面有多篇文章,這也是典型的一對多;一個欄目下面有多個內容,這也是典型的一對多。
  6. 。。。再有的話,歡迎評論。

以項目人員爲示例

項目人員表


業務需求

咱們只有點擊選擇人員,纔將數據保存到數據庫中,可是,咱們仍是要將人員類型按照順序展現出來。於是,咱們須要考慮的是,判斷數據庫中是否存在某種人員類型,好比業務員類型,業務部經理類型。

  • 存在,就把數據表的對象取出來,而後填充到集合容器中。
  • 不存在,咱們就要把數據庫中不存在的人員類型填充到集合容器中。

算法思想:

在作項目以前,咱們須要考慮算法,不然,作出來的東西雖然沒錯,但不是業務所須要的。

  1. 咱們從數據庫中取出當前項目下的項目人員的記錄,即 List<ProjectPerson> projectList = projectPersonDao.listProjectPersons(projectId);
  2. 咱們獲取枚舉對象的數組,而後遍歷枚舉集合,即 for (PersonTypeEnum obj : PersonTypeEnum.class.getEnumConstants());
  3. 設置一個開關,true 表示數據存在該枚舉對象,false 表示數據庫不存在該枚舉對象,即 boolean objInProjectPerson = false;
  4. 再遍歷projectList ,獲取項目人員的對象,拿到人員類型的對象,與枚舉對象進行比較,若是相等,就objInProjectPerson置爲true,而後挑出內循環。
  5. 判斷objInProjectPerson狀態,若是未false,就將人員類型的對象設置爲當前枚舉對象。
  6. 最後,經過 projectPersonList.sort(Comparator<? super E> c)方法進行排序。由於方法形參的是Comparator接口,於是,咱們須要一方法內部類的方式實現排序。

方法實現

經過上文的算法設計,咱們編寫實現方法:

@Override
    public Result<List<ProjectPerson>> listProjectPersons(Long projectId) {
//        【1】步驟一
        List<ProjectPerson> projectList = projectPersonDao.listProjectPersons(projectId);
        List<ProjectPerson> projectPersonList = new ArrayList<>();
        Class<PersonTypeEnum> clz = PersonTypeEnum.class;
        //        【2】步驟二
        for (PersonTypeEnum obj : clz.getEnumConstants()) {
            //        【3】步驟三
            boolean objInProjectPerson = false;
            for (ProjectPerson projectPerson : projectList) {
                //        【4】步驟四
                if (obj.equals(projectPerson.getPersonType())) {
                    projectPerson.setSort(obj.ordinal());
                    objInProjectPerson = true;
                    projectPersonList.add(projectPerson);
                    break;
                }
            }
            //        【5】步驟五
            if (!objInProjectPerson) {
                ProjectPerson projectPerson = new ProjectPerson();
                projectPerson.setPersonType(obj);
                projectPerson.setSort(obj.ordinal());
                projectPersonList.add(projectPerson);
            }
        }
        //        【6】步驟6
        projectPersonList.sort(new Comparator<ProjectPerson>() {
            @Override
            public int compare(ProjectPerson firstProjectPerson, ProjectPerson secondProjectPerson) {
                return firstProjectPerson.getSort() - secondProjectPerson.getSort();
            }
        });
        return ResultUtil.buildSuccess(projectPersonList);
    }

總結

咱們在開發過程當中和,要分明白什麼時候以業務驅動爲開發對象,什麼時候以算法驅動爲開發對象。這樣,作一個有條理的人,你就會得到更多的知識。

相關文章
相關標籤/搜索