1. 程式人生 > >jpa多表關係 一對多 多對多 一對一 註解怎麼寫

jpa多表關係 一對多 多對多 一對一 註解怎麼寫

一、多表關係

1、一對多

       一方放棄外來鍵維護,多方來維護,預設雙方都有外來鍵維護權力,一方選擇放棄就行,避免重複更新 提高效能 

       多方表加入外來鍵欄位,該欄位值和一方表id一致,但外來鍵欄位在實體中並沒有宣告屬性,也就是說多方實體內沒有外來鍵欄位屬性,但會使用@JoinColumn(name="bid")  指出外來鍵的名字;

         多方維護外來鍵,怎麼維護呢?

         程式碼中,stu.setBj(b1);  //b1為班級

         然後儲存stu 就是維護外間了,b1如果是新建的,系統會先儲存b1 再儲存stu的同時設定外來鍵,如果b1本來就存在,那就直接儲存b1了

        維護外來鍵和級聯怎麼區分?

        接著上邊的說,如果stu設定了級聯(分級別的,這裡預設所有庫操作都級聯),當儲存的時候stu的時候,stu.setBj(b1) 即代表級聯,又代表維護外來鍵,都要先儲存b1(如果是新建的),  刪除的時候,根據id 名字這類刪除stu時,就會把b1也刪除了,

查詢的時候 不管設沒設級聯,stu實體中都會封裝b1

        b.setStu(stu1); 這個能儲存嘛?  其實直接儲存b  讓stu為空 就是單表操作了,如果設定stu1 ,b本身是不能維護外來鍵的,所以還要先 stu1.setBj(b),然後 b.setStu(stu1) ,然後 儲存stu1 、b才行,等於說要加維護外來鍵,這有點脫褲子放屁了,儲存stu1的時候由於維護外來鍵b就已經同時儲存了,那還儲存b幹嘛? ,如果配置了級聯,只儲存b即可,不用顯示儲存stu1,但後臺還是先儲存stu1 再儲存b 的;

          要是班級配置級聯的話,根據id 名字啥地刪除一個班級,就會把相應的學生也刪除了;如果沒配置級聯,刪除班級,如果該班級有關聯的學生,那麼報錯無法刪除,所以後臺邏輯先去學生表裡按照班級id查詢出關聯的學生,把bid 重置為空,再刪除該班級;

      級聯就是儲存的時候先儲存你再儲存我,刪除的時候先刪除你再刪除我,對於一對多來說,一方配置了級聯,儲存刪除的時候就會先儲存或者刪除多方,操作多方這時候就會維護外來鍵,然後再刪除一方那就是單表操作了;

        

例如:一個班級有多個學生,一個學生只能在一個班   雙向關聯

@Entity

@Table(name="bclass")

Bclass {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)

     string id  ;   //班級id

     @Column(name="name")

     string name;//班級名字

    @OneToMany(mappedBy="Bclass",cascade = CascadeTye.ALL,optional = true)  
 //mappedBy 就是放棄外來鍵維護權的意思  cascade 級聯    optional該值是否可以為空,true可以

     Set<Stu> set = new HashSet<Stu>();// 班級裡的學生
    // set  get 省略

}

 

@Entity

@Table(name="bclass")

stu {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)

     string id  ;   //

     @Column(name="name")

     string name;//學生名字

    @ManyToOne(cascade = CascadeTye.ALL,optional = true)  
    @JoinColumn(name="bid") //joincolum  jointable都是代表維護外來鍵的意思  
    //不能和 mappeyBy同時使用  總不能即放棄又選擇外來鍵維護權

    Bclass bj ;
    // set  get 省略

}

 業務邏輯:

如果沒有學生:那麼班級的新建、刪除、修改等都是單表操作

如果有學生:新建是單表操作,刪除就要先去學生表把關聯的置空了,再刪除班級,編輯也是單表操作(id沒變嘛),stu實體中bj屬性要能為空,才能滿足班級能刪除

一對多必須有多方維護外來鍵嘛?

一方可以放棄維護外來鍵,也可以不放棄,但多方無法放棄維護外來鍵,只能維護,因為 @ManyToOne 沒有mapperBy屬性,無法放棄;所以總的來說,要麼多方自己維護,要麼兩一塊維護,但一起維護會產生多餘sql 影響效能

一起維護,多方寫法不變,一方如下,mapperBy換作joinColumn了

@OneToMany

@JoinColumn(name="bid")//寫的也是表的外來鍵欄位名

private Set <Stu> stuSet = new HashSet<Stu>();

2、多對多

必須有一方放棄外來鍵維護,不然報錯,多對多不是新增一個外來鍵欄位,而是新建了一張中間表

@ManyToMany

@JoinTable(name = “student_teacher”, inverseJoinColumns = @JoinColumn(name = “tid”), joinColumns = @JoinColumn(name = “sid”)) 

private Set<xx> xxSet = new hashSet<xx>(); 
/*

有joinTable和joinColumn就是維護外來鍵的一方了, A.setXX() 就代表維護外來鍵
name:是關係表的名字 
joinColumns:自己這一端的主鍵 
inverseJoinColumns:對方的主鍵
/*

不維護外來鍵的一方怎麼寫,例如雙向關聯

@ManyToMany(mappedBy = "自己類的名字,代表放棄外來鍵維護")

private xxxxxxx

如果是單向關聯,不維護外來鍵的一方,@ManyToMany都不用寫,就是一個普通的類了

 

3、一對一

如果是外來鍵關聯,雙方使用的都是@OneToOne  ,這注解有mapperBy屬性可以放棄外來鍵維護,當然雙方也都可以使用joincolumn ,所以誰都可以放棄,誰都可以獲得,大致和一對多差不多

如果是主鍵關聯,就是兩個表的主鍵必須一直,例如user表拆分為user表和userInfo表,咱們可以讓userinfo表的主鍵依靠user的主鍵來生成

一對一主鍵雙向關聯

User 對應UserInfo userInfo的主鍵跟隨User

User方:

@OneToOne(cascade=CascadeType.ALL)

@PrimaryKeyJoinColumn //這個註解只能寫在主(生成ID)的一端

private UserInfo userInfo;//一對一 使用者與擴充套件資訊 基於主鍵一對一

User方的主鍵配置為自動策略,正常配置

 

 

UserInfo方:

@OneToOne(mappedBy="userInfo")

@JoinColumn(name="USER_INFO_ID",referencedColumnName="USER_ID")//這句可省略??

private User user;

 

UserInfo的主鍵根據關聯user的外來鍵生成

配置為

@Id

@Column(name="USER_INFO_ID")

@GenericGenerator(name="pkGenerator",strategy="foreign",parameters={@Parameter(name="property",value="user")}) user就是本實體內user屬性

@GeneratedValue(generator="pkGenerator")

private String id;