Недавно мы столкнулись с сложной ситуацией с отображением ассоциации гибернации с помощью составного поля идентификатора. Нам нужно было иметь двунаправленную связь с «один к одному» и «многие к одному». Наши таблицы буксировки были «REPORT» и «REPORT_SUMMARY», которые имеют отношение «один ко многим» от REPORT до REPORT_SUMMARY и отношение «многие к одному» от REPORT_SUMMARY в таблицу REPORT. Первичный ключ таблицы REPORT_SUMMARY определяется как составной первичный ключ, который состоит из поля идентификатора автоматического увеличения и первичного ключа таблицы REPORT.
1
2
3
4
5
|
CREATE TABLE REPORT ( ID INT( 10 ) NOT NULL AUTO_INCREMENT, NAME VARCHAR( 45 ) NOT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
1
2
3
4
5
6
|
CREATE TABLE REPORT_SUMMARY ( ID INT( 10 ) NOT NULL AUTO_INCREMENT, NAME VARCHAR( 45 ) NOT NULL, RPT_ID INT( 10 ) NOT NULL, PRIMARY KEY (`ID`,`RPT_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
Спящие классы сущностей как пара.
Report.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package com.semika.autoac.entities; import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class Report implements Serializable{ private static final long serialVersionUID = 9146156921169669644L; private Integer id; private String name; private Set<ReportSummary> reportSummaryList = new HashSet<ReportSummary>(); public Integer getId() { return id; } public void setId(Integer id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } public Set<ReportSummary> getReportSummaryList() { return reportSummaryList; } public void setReportSummaryList(Set<ReportSummary> reportSummaryList) { this .reportSummaryList = reportSummaryList; } } |
ReportSummary.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
package com.semika.autoac.entities; import java.io.Serializable; public class ReportSummary implements Serializable { private static final long serialVersionUID = 8052962961003467437L; private ReportSummaryId id; private String name; public ReportSummaryId getId() { return id; } public void setId(ReportSummaryId id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } @Override public int hashCode() { final int prime = 31 ; int result = 1 ; result = prime * result + ((id == null ) ? 0 : id.hashCode()); result = prime * result + ((name == null ) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if ( this == obj) return true ; if (obj == null ) return false ; if (getClass() != obj.getClass()) return false ; ReportSummary other = (ReportSummary) obj; if (id == null ) { if (other.id != null ) return false ; } else if (!id.equals(other.id)) return false ; if (name == null ) { if (other.name != null ) return false ; } else if (!name.equals(other.name)) return false ; return true ; } } |
ReportSummaryId.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package com.semika.autoac.entities; import java.io.Serializable; public class ReportSummaryId implements Serializable{ private static final long serialVersionUID = 6911616314813390449L; private Integer id; private Report report; public Integer getId() { return id; } public void setId(Integer id) { this .id = id; } public Report getReport() { return report; } public void setReport(Report report) { this .report = report; } @Override public int hashCode() { final int prime = 31 ; int result = 1 ; result = prime * result + ((id == null ) ? 0 : id.hashCode()); result = prime * result + ((report == null ) ? 0 : report.hashCode()); return result; } @Override public boolean equals(Object obj) { if ( this == obj) return true ; if (obj == null ) return false ; if (getClass() != obj.getClass()) return false ; ReportSummaryId other = (ReportSummaryId) obj; if (id == null ) { if (other.id != null ) return false ; } else if (!id.equals(other.id)) return false ; if (report == null ) { if (other.report != null ) return false ; } else if (!report.equals(other.report)) return false ; return true ; } } |
Объект отчета имеет коллекцию объектов ReportSummary, а ReportSummaryId имеет ссылку на объект Report. Самая важная часть этой реализации — это отображающие файлы в спящем режиме. Report.hbm.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<? xml version = "1.0" ?> <! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" < hibernate-mapping > < class name = "com.semika.autoac.entities.Report" table = "REPORT" > < id name = "id" type = "int" column = "id" > < generator class = "native" /> </ id > < property name = "name" > < column name = "NAME" /> </ property > < set name = "reportSummaryList" table = "REPORT_SUMMARY" cascade = "all" inverse = "true" > < key column = "RPT_ID" not-null = "true" ></ key > < one-to-many class = "com.semika.autoac.entities.ReportSummary" /> </ set > </ class > </ hibernate-mapping > |
ReportSummary.hbm.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<? xml version = "1.0" ?> <! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" < hibernate-mapping > < class name = "com.semika.autoac.entities.ReportSummary" table = "REPORT_SUMMARY" > < composite-id name = "id" class = "com.semika.autoac.entities.ReportSummaryId" > < key-property name = "id" column = "ID" ></ key-property > < key-many-to-one name = "report" class = "com.semika.autoac.entities.Report" column = "RPT_ID" </key-many-to-one> </ composite-id > < property name = "name" > < column name = "NAME" /> </ property > </ class > </ hibernate-mapping > |
Ссылка: Как использовать Hibernate для составных идентификаторов с сопоставлениями ассоциаций от нашего партнера JCG Семика Локу Калуге в блоге Code Box .