Question

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;
    }
}
Was it helpful?

Solution

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.

OTHER TIPS

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..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top