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;