在使用hibernate和jpa的spring mvc应用程序中,WordKey
实体和Concept
实体之间存在多对多的关系。 WordKey
有concepts
个集合,Concept
有wordkeys
个集合。我不想使用fetchType=EAGER
,因为性能是一个问题。相反,一旦用户选择了WordKey
,我希望使用Collection<Concept>
selectedKeyWord
作为参数的查询结果填充wk
并返回与基础数据库中的concepts
关联的WordKey
集合。如何在JPQL中编写此查询?
这是我到目前为止的查询。它不起作用(见下面的错误):
@SuppressWarnings("unchecked")
public Collection<Concept> findConceptsForKeyWord(ConcWordKey wk) {
Query query = this.em.createQuery(
"SELECT DISTINCT concept FROM Concept concept join concept.wordkeys k WHERE k.name =:wk"
);
query.setParameter("wk", wk.getName());
Collection<Concept> result = (Collection<Concept>) query.getResultList();
return result;
}
以下是上述代码生成的hibernate查询。请注意,它正在寻找一个虚构的concept_wordkey
表,而不是使用下面wordkey_junction
实体代码中指定的WordKey
连接表:
select distinct conc0_.effectiveTime as effectiv1_52_,
conc0_.id as id2_52_,
from concept conc0_
inner join concept_wordkey wordkeys1_
on conc0_.effectiveTime=wordkeys1_.concept_effectiveTime
and conc0_.id=wordkeys1_.concept_id
inner join wordkey conc2_
on wordkeys1_.wordkeys_keyword=conc2_.keyword
where conc2_.keyword=?
堆栈跟踪中生成的特定错误是:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Table 'mydb.concept_wordkey' doesn't exist
以下是Concept
实体:
@Entity
@Table(name = "concept")
public class Concept implements Serializable{
@EmbeddedId
public EmbedPK conceptPk;
@ManyToMany(cascade={CascadeType.ALL})
private Set<WordKey> wordkeys;
public EmbedPK getConceptPk(){return conceptPk;}
protected Set<WordKey> getWordkeysInternal() {
if (this.wordkeys == null) {this.wordkeys = new HashSet<WordKey>();}
return this.wordkeys;
}
public List<WordKey> getWordkeys() {
List<WordKey> sortedWordkeys = new ArrayList<WordKey>(getWordkeysInternal());
PropertyComparator.sort(sortedWordkeys, new MutableSortDefinition("wordkey", true, true));
return Collections.unmodifiableList(sortedWordkeys);
}
public WordKey getWordkey(String s) {return getWordkey(s, false);}
public WordKey getWordkey(String ps, boolean ignoreNew) {
ps = ps.toLowerCase();
for (WordKey s1 : getWordkeysInternal()) {
if (!ignoreNew || !s1.isNew()) {
String keyword = s1.getName();
keyword = keyword.toLowerCase();
if (keyword.equals(ps)) {return s1;}
}
}
return null;
}
}
以下是WordKey
实体:
@Entity
@Table(name = "wordkey")
public class WordKey {
@Id
@Column(name="keyword")
private String name;
@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name="wordkey_junction",
joinColumns={@JoinColumn(name="keyword")},
inverseJoinColumns={@JoinColumn(name="conceptid"),@JoinColumn(name="effectiveTime")})
private Set<Concept> concepts = new HashSet<Concept>();
public String getName(){return name;}
public void setName(String nm){name=nm;}
protected Set<Concept> getConceptsInternal() {
if (this.concepts == null) {this.concepts = new HashSet<Concept>();}
return this.concepts;
}
public List<Concept> getConcepts() {
List<Concept> sortedConcepts = new ArrayList<Concept>(getConceptsInternal());
PropertyComparator.sort(sortedConcepts, new MutableSortDefinition("conceptid", true, true));
return Collections.unmodifiableList(sortedConcepts);
}
public Concept getConcept(BigInteger s) {return getConcept(s, false);}
public Concept getConcept(BigInteger ps, boolean ignoreNew) {
for (Concept s1 : getConceptsInternal()) {
if (!ignoreNew || !s1.isNew()) {
BigInteger compName = s1.getConceptPk().getId();
if (compName == ps) {return s1;}
}
}
return null;
}
}
答案 0 :(得分:3)
我认为您的@ManyToMany(cascade={CascadeType.ALL})
课程中的Concept
需要一个mappedBy。添加将注释更改为@ManyToMany(cascade={CascadeType.ALL}, mappedBy="concepts")
并再次尝试。
你需要这个来告诉Hibernate将你的多对多wordKey
集合映射到Concept
类的WordKey
集合,这将依次将您的wordkey_junction
表暴露给集合。
如果这不起作用或您不想要双向关系,请告诉我。
答案 1 :(得分:2)
您需要指定mid(外部参照)表。
@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name = "midTableName",
joinColumns = {@JoinColumn(name = "foreignKey")},
inverseJoinColumns = {@JoinColumn(name = "OtherEntityForeignKey")})
注意 - 这是具有规范化的ManyToMany Mapping的一般方式。如果你能用表结构更新问题,你可以得到一个好的答案。