Reputation: 9201
In a spring mvc application using hibernate and jpa, I have a many to many relationship between a WordKey
entity and a Concept
entity. WordKey
has a concepts
collection, and Concept
has a wordkeys
collection. I DO NOT want to use fetchType=EAGER
because performance is an issue. Instead, once a WordKey
has been selected by a user, I want to populate a Collection<Concept>
with the results of a query that takes selectedKeyWord
wk
as a parameter and returns the collection of concepts
that is associated with that WordKey
in the underlying database. How do I write this query in JPQL?
Here is the query that I have so far. It is not working (see error further below):
@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;
}
Here is the hibernate query that is being generated by the above code. Note that it is looking for an imaginary concept_wordkey
table instead of using the wordkey_junction
join table that is specified in the WordKey
entity code further below:
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=?
The specific error being generated in the stack trace is:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:
Table 'mydb.concept_wordkey' doesn't exist
Here is the Concept
entity:
@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;
}
}
Here is the WordKey
entity:
@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;
}
}
Upvotes: 2
Views: 765
Reputation: 2209
You need to Specify mid (xref) Table.
@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name = "midTableName",
joinColumns = {@JoinColumn(name = "foreignKey")},
inverseJoinColumns = {@JoinColumn(name = "OtherEntityForeignKey")})
Note -This is the General way of ManyToMany Mapping with normalization. you can get a Good answer if you can update the question with table structure..
Upvotes: 2
Reputation: 6540
I think you need a mappedBy in your @ManyToMany(cascade={CascadeType.ALL})
in your Concept
class. Add change your annotation to @ManyToMany(cascade={CascadeType.ALL}, mappedBy="concepts")
and try it again.
You need this to tell Hibernate to map your many-to-many collection of wordKey
's to the collection of Concept
's on the WordKey
class, which will in turn expose your wordkey_junction
table to the collection.
If that doesn't work or you don't want a bidirectional relationship, let me know.
Upvotes: 3