Hibernate - ManyToOne&继承/ JOINED / mappedBy

时间:2014-03-07 13:57:39

标签: java mysql spring hibernate maven

我在继承映射方面遇到了一些问题。这是我的数据库结构:

enter image description here

及相关实体:

AbstractEntity:

@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;
}

UserAcitvity实体:

@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_questionuser_answer不需要

我应该为修复做些什么?

4 个答案:

答案 0 :(得分:4)

我认为您无法通过将ManyToOne关联映射到User实体中的UserActivity来实现此目的。这对于JPA提供者(Hibernate)来说可能太混乱了。

相反,我认为您需要将关联映射到UserQuestionAnswer实体的每个中的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<>();

同样适用于AnswerComment

当然,我没试过,所以我错了。

答案 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.userUser.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<>();