由于标题可能有点模糊,这里是对我的问题的解释(这不容易归纳为简洁的标题)。
我的问题很简单(我想要达到的目的对我来说似乎非常直观),尽管解决它可能不是。我有两个代表绑定概念的抽象类。作为一个例子,我选择Project和Task。给定项目可以有许多任务。这些类是抽象的,因为有不同类型的项目和不同类型的任务,但项目和任务类型是相同的。例如,有开发项目和开发任务(可能看起来有点奇怪,但这是一个简化的例子)。当然还有其他类型的项目和任务,但让我们坚持这些。
我想要实现的是用JPA映射我在两个抽象类中的关系,并在具体类中从中受益。使事情变得复杂的是我还必须映射继承:带有鉴别器的单个表,它也是类ID的一部分。我将泛型类型添加到抽象类中,以确保我可以强制具体类引用正确的关联类(与DeveloperTask绑定的DevelopmentProject)。
问题是,无论我尝试什么,我总会得到某种错误。我在这里寻求的是那些已经取得这样成绩的人。我必须告诉你,我正在使用遗留数据库(我很清楚当前的设计存在很多问题,但遗憾的是我无能为力)。
为了帮助您,我加入了我制作的示例代码,这样您就会看到我在上面的段落中的含义。
@Entity
@Table(name = "PROJECT")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.INTEGER)
public abstract class Project<T extends Task> {
/* Fields */
private ProjectId id;
private List<T> tasks;
/* Constructors */
protected Project() {}
public Project(ProjectId id) {
this.id = id;
}
/* Getters */
@EmbeddedId
public ProjectId getId() {
return id;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy = "project", targetEntity = Task.class)
public List<T> getTasks() {
return tasks;
}
/* Setters */
public void setTasks(List<T> tasks) {
this.tasks = tasks;
}
}
@Embeddable
public class ProjectId {
/* Fields */
private Integer type;
private Integer number;
/* Constructors */
@SuppressWarnings("unused")
private ProjectId() {} /* Empty constructor for hibernate */
public ProjectId(Integer type, Integer number) {
this.type = type;
this.number = number;
}
/* Getters */
@Column(name = "TYPE", nullable = false)
private Integer getType() { /* Only for Hibernate */
return type;
}
@Column(name = "NUMBER", nullable = false)
public Integer getNumber() {
return number;
}
/* Setters */
@SuppressWarnings("unused")
private void setType(Integer type) { /* Only for Hibernate */
this.type = type;
}
public void setNumber(Integer number) {
this.number = number;
}
}
@Entity
@Table(name = "TASK")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.INTEGER)
public abstract class Task<P extends Project> {
/* Fields */
private TaskId id;
private P project;
/* Constructors */
protected Task() {}
public Task(TaskId id) {
this.id = id;
}
/* Getters */
@EmbeddedId
public TaskId getId() {
return id;
}
@ManyToOne(fetch = FetchType.EAGER, optional = false, targetEntity = Project.class)
@JoinColumns({
@JoinColumn(name = "TYPE", referencedColumnName = "TYPE", insertable = false, updatable = false),
@JoinColumn(name = "PROJECT_NUMBER", referencedColumnName = "NUMBER", insertable = false, updatable = false)
})
public P getProject() {
return project;
}
/* Setters */
public void setId(TaskId id) {
this.id = id;
}
public void setProject(P project) {
this.project = project;
}
}
@Embeddable
public class TaskId {
/* Fields */
private Integer type;
private Integer projectNumber;
private Integer number;
/* Constructors */
@SuppressWarnings("unused")
private TaskId() {} /* Empty constructor for Hibernate */
public TaskId(Integer type, Integer projectNumber, Integer number) {
this.type = type;
this.projectNumber = projectNumber;
this.number = number;
}
/* Getters */
@Column(name = "TYPE", nullable = false)
private Integer getType() { /* Only for Hibernate */
return type;
}
@Column(name = "PROJECT_NUMBER", nullable = false)
public Integer getProjectNumber() {
return projectNumber;
}
@Column(name = "NUMBER", nullable = false)
public Integer getNumber() {
return number;
}
/* Setters */
@SuppressWarnings("unused")
private void setType(Integer type) { /* Only for Hibernate */
this.type = type;
}
public void setProjectNumber(Integer projectNumber) {
this.projectNumber = projectNumber;
}
public void setNumber(Integer number) {
this.number = number;
}
}
@Entity
@DiscriminatorValue(value = "1")
public class DevelopmentProject extends Project<DevelopmentTask> {
/* Constructors */
@SuppressWarnings("unused")
private DevelopmentProject() { /* Empty constructor for Hibernate */
super();
}
public DevelopmentProject(DevelopmentProjectId id) {
super(id);
}
}
public class DevelopmentProjectId extends ProjectId {
/* Constructors */
public DevelopmentProjectId(Integer number) {
super(1, number); /* Development type is forced */
}
}
@Entity
@DiscriminatorValue(value = "1")
public class DevelopmentTask extends Task<DevelopmentProject> {
/* Constructors */
@SuppressWarnings("unused")
private DevelopmentTask() { /* Empty constructor for Hibernate */
super();
}
public DevelopmentTask(DevelopmentTaskId id) {
super(id);
}
}
public class DevelopmentTaskId extends TaskId {
/* Constructors */
public DevelopmentTaskId(Integer number) {
super(1, number); /* Development type is forced */
}
}
编辑: 我稍微纠正了我的例子(将一个projectNumber添加到Task,没有它,这种关系似乎毫无意义,甚至是错误的)。我还在我的关系中添加了targetEntity(我忘记了,你会在下面看到原因)。
现在我将尝试向你解释我的路径。
我真的很想知道是否有人尝试过这样的事情并取得成功,即使解决方案不同,因为它尽可能方便和优雅。