我在继承映射方面遇到了一些问题。这是我的数据库结构:
及相关实体:
@MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
@Id @GeneratedValue(strategy = IDENTITY)
@Column(unique = true, updatable = false, nullable = false)
private ID id;
public ID getId() {
return id;
}
@SuppressWarnings("unused")
public void setId(ID id) {
this.id = id;
}
@Entity @Table(name = "user_activity")
@Inheritance(strategy = JOINED)
@AttributeOverride(name = "id", column = @Column(name = "ua_id"))
public abstract class UserActivity extends AbstractEntity<Long> {
@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "ua_user_id")
private User user;
...
}
@Entity @Table(name = "comment")
@PrimaryKeyJoinColumn(name = "cm_id")
public class Comment extends UserActivity {
@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "cm_question_id")
private Question question;
...
}
@Entity @Table(name = "question")
@PrimaryKeyJoinColumn(name = "qs_id")
public class Question extends UserActivity {
...
@OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "question")
private List<Answer> answers = new ArrayList<>();
@OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "question")
private List<Comment> comments = new ArrayList<>();
...
}
@Entity @Table(name = "answer")
@PrimaryKeyJoinColumn(name = "asw_id")
public class Answer extends UserActivity {
@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "asw_question_id")
private Question question;
...
}
@Entity @Table(name = "user")
@AttributeOverride(name = "id", column = @Column(name = "user_id"))
public class User extends AbstractEntity<Long> {
...
@OneToMany(cascade = REMOVE)
private List<Question> questions = new ArrayList<>();
@OneToMany(cascade = REMOVE)
private List<Answer> answers = new ArrayList<>();
@OneToMany(cascade = REMOVE)
private List<Comment> comments = new ArrayList<>();
...
}
当我尝试保存或删除User
时,我得到例外情况:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into user_question (user_user_id, questions_qs_id) values (?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
和
org.hibernate.engine.jdbc.spi.SqlExceptionHelper : 147 = user lacks privilege or object not found: USER_ANSWER
Hibernate正在尝试创建一个表格:user_question
和user_answer
我不需要。
我应该为修复做些什么?
答案 0 :(得分:4)
我认为您无法通过将ManyToOne
关联映射到User
实体中的UserActivity
来实现此目的。这对于JPA提供者(Hibernate)来说可能太混乱了。
相反,我认为您需要将关联映射到User
,Question
和Answer
实体的每个中的Comment
。是的,我知道这将是重复的代码,但它似乎是您能够使用OneToMany
引用在User
中限定mappedBy
映射的唯一方式。
例如,您的Question
实体将关联定义为:
@ManyToOne(cascade = { MERGE, PERSIST }, fetch = LAZY)
@JoinColumn(name = "ua_user_id")
private User questionUser;
根据Hibernate对上述关联的巧妙(或不),您可能需要在table="USER_ACTIVITY"
注释中指定JoinColumn
。
然后User
将OneToMany作为:
@OneToMany(mappedBy="questionUser", cascade = REMOVE)
private List<Question> questions = new ArrayList<>();
同样适用于Answer
和Comment
。
当然,我没试过,所以我错了。
答案 1 :(得分:2)
可能会发生这种情况,因为当您设置@OneToMany映射时,hibernate将创建一个辅助表,该表将存储关系中实体的id。
在这种情况下,您应该尝试以下方法:
@OneToMany(cascade = REMOVE)
@JoinColumn(name = "answer_id")
private List<Answer> answers = new ArrayList<>();
@JoinColumn注释将在不创建辅助表的情况下映射关系,因此在这种情况下,此解决方案很可能会帮助您。
答案 2 :(得分:1)
尝试此映射,根据section 2.2.5.3.1.1 of the documentation:
,这应该可以正常工作@Entity
public class User {
@OneToMany(cascade = REMOVE)
@JoinColumn(name="user_fk") //we need to duplicate the physical information
private List<Question> questions = new ArrayList<>();
...
}
@Entity
public class Question {
@ManyToOne
@JoinColumn(name="user_fk", insertable=false, updatable=false)
private User user;
...
}
创建辅助关联的原因是,Hibernate无法知道关系的多边(例如Question)有一个返回给User的外键,它对应于与{完全相同的关系{1}}。
关联User.questions
可能是完全不同的关联,例如Question.user
或User.questionCreator
。
仅仅通过查看User.previousSuccessfulAnswerer
,Hibernate就无法知道它与Question.user
具有相同的关联。
因此,如果User.questions
表示关系相同,或者mappedBy
表示没有连接表(但只有连接列),Hibernate将触发通用的一对一许多关联映射解决方案,包括创建辅助映射表。
架构错过了这样的关联表,导致错误可以通过上面的映射解决。
答案 3 :(得分:0)
如果您希望在实体关系中使用单向一对多用法 试试.. JoinTable
@OneToMany(cascade = REMOVE)
@JoinTable(name = "user_question", joinColumns = {
@JoinColumn(name = "user_id")}, inverseJoinColumns = {
@JoinColumn(name = "qs_id")})
private List<Question> questions = new ArrayList<>();