Pablo,
我们公司正在将现有的Spring/MyBatis代码转换为Spring Data JPA,因此我已经学习了几周的Spring Data JPA。虽然我不是专家,但我已经解决了一个类似于你的示例,它可能会对你有所帮助。
我拥有与你相似的Person和Company类,但是(正如Jens所提到的),你需要使用带有OneToMany注释的列表。我使用了一个单独的连接表(名为company_person),它只有companyId、personId两列,以维护多对多关系。请查看下面的代码。
我没有找到一种在company_person连接表中放置开始/结束日期的方法,因此我为此创建了一个单独的(第四个)表。我称之为employment_record,Java类实体为EmploymentRecord。它具有组合主键(companyId、personId)和开始/结束日期。
您需要为Person、Company和EmploymentRecord编写存储库。我扩展了CrudRepository而不是JpaRepository。但是,您不需要为连接表(company_record)创建实体或存储库。
我制作了一个Spring Boot应用程序类来测试它。我在Person的OneToMany上使用了CascadeType.ALL。在我的应用程序测试中,我测试了我可以更改分配给人员的公司,并且Spring Data会传播到Company实体和连接表所需的所有更改。
但是,我必须通过其存储库手动更新EmploymentRecord实体。例如,每次将公司添加到人员时,我必须添加一个start_date。然后,在从该人员中删除该公司时添加end_date。可能有一种自动化此过程的方法。Spring/JPA审核功能是一种可能性,因此请查看它。
回答你的问题:
如何检索特定公司的雇员列表(我对人员属性感兴趣)?
您只需使用companyRepository的findOne(Long id)方法,然后使用getPersonList()方法即可。
来自Application.java的片段:
PersonRepository pRep = context.getBean(PersonRepository.class);
CompanyRepository cRep = context.getBean(CompanyRepository.class);
EmploymentRecordRepository emplRep = context.getBean(EmploymentRecordRepository.class);
...
Company comp = cRep.findOne(5L);
System.out.println("Found a company using findOne(5L), company= " + comp.getName());
System.out.println("People who work at " + comp.getName());
for (Person p : comp.getPersonList()) {
System.out.println(p);
}
以下是我发现的一些有用参考资料:
Spring Data JPA教程
连接表示例
Person.java:
@Entity
public class Person {
Person() { }
public Person(String name, String address) {
this.name = name;
this.address = address;
}
@Id
@GeneratedValue
private Long id;
@Column(name = "name")
private String name;
@Column(name = "address")
private String address;
@Version
private int versionId;
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name="company_person",
joinColumns={@JoinColumn(name="person_id", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="company_id", referencedColumnName="id")})
private List<Company> companyList;
}
Company.java:
@Entity
public class Company {
Company() { }
public Company(String name, String address) {
this.name = name;
this.address = address;
}
@Id
@GeneratedValue
private Long id;
@Column(name = "name")
private String name;
@Column(name = "address")
private String address;
@Version
private int versionId;
@OneToMany(fetch = FetchType.EAGER)
@JoinTable(name="company_person",
joinColumns={@JoinColumn(name="company_id", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="person_id", referencedColumnName="id")})
private List<Person> personList;
}
EmploymentRecord.java:
@Entity
@IdClass(EmploymentRecordKey.class)
public class EmploymentRecord {
EmploymentRecord() { }
public EmploymentRecord(Long personId, Long companyId, Date startDate, Date endDate) {
this.startDate = startDate;
this.endDate = endDate;
this.companyId = companyId;
this.personId = personId;
}
@Id
@Column(name = "company_id", nullable = false)
private Long companyId;
@Id
@Column(name = "person_id", nullable = false)
private Long personId;
@Column(name = "start_date")
private Date startDate;
@Column(name = "end_date")
private Date endDate;
@Version
private int versionId;
@Override
public String toString() {
return
" companyId=" + companyId +
" personId=" + personId +
" startDate=" + startDate +
" endDate=" + endDate +
" versionId=" + versionId;
}
}
class EmploymentRecordKey implements Serializable {
private long companyId;
private long personId;
EmploymentRecordKey() { }
@Override
public int hashCode() {
return (int) ((int) companyId + personId);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (!(obj instanceof EmploymentRecordKey)) return false;
EmploymentRecordKey pk = (EmploymentRecordKey) obj;
return pk.companyId == companyId && pk.personId == personId;
}
}
MySql脚本,createTables.sql:
DROP TABLE IF EXISTS `test`.`company_person`;
DROP TABLE IF EXISTS `test`.`employment_record`;
DROP TABLE IF EXISTS `test`.`company`;
DROP TABLE IF EXISTS `test`.`person`;
CREATE TABLE `company` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL DEFAULT '',
`address` varchar(500) DEFAULT '',
`version_id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `person` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL DEFAULT '',
`address` varchar(500) DEFAULT '',
`version_id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `company_person` (
`company_id` int NOT NULL,
`person_id` int NOT NULL,
PRIMARY KEY (`person_id`,`company_id`),
KEY `company_idx` (`company_id`),
KEY `person_idx` (`person_id`),
CONSTRAINT `fk_person` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `employment_record` (
`company_id` int NOT NULL,
`person_id` int NOT NULL,
`start_date` datetime,
`end_date` datetime,
`version_id` int NOT NULL,
PRIMARY KEY (`person_id`,`company_id`),
KEY `empl_company_idx` (`company_id`),
KEY `empl_person_idx` (`person_id`),
CONSTRAINT `fk_empl_person` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_empl_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Person
到CompanyEmployee
的引用和Company
到CompanyEmployee
的引用都添加进去。 - Jens