2014-05-15 62 views
2

在使用hibernate和jpa的spring mvc应用程序中,我在WordKey实体和Concept实体之间存在多对多的关系。 WordKey有一个concepts集合,而Concept有一个wordkeys集合。我不想使用fetchType=EAGER,因为性能是一个问题。相反,一旦用户选择了WordKey,我想用查询的结果填充Collection<Concept>,查询的结果为selectedKeyWordwk作为参数,并返回底层数据库中与WordKey关联的集合concepts。我如何在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; 
    } 
} 

回答

3

我认为你需要在你的@ManyToMany(cascade={CascadeType.ALL})一个的mappedBy在Concept类。添加更改您的注释到@ManyToMany(cascade={CascadeType.ALL}, mappedBy="concepts")并再试一次。

你需要这个来告诉Hibernate来你的许多一对多的集合wordKey映射的到的Concept集合“的WordKey S级,这将反过来你wordkey_junction表暴露到集合中。

如果这不起作用或者您不想要双向关系,请告诉我。

2

您需要指定mid(xref)表。

@ManyToMany(cascade = {CascadeType.ALL}) 
    @JoinTable(name = "midTableName", 
      joinColumns = {@JoinColumn(name = "foreignKey")}, 
      inverseJoinColumns = {@JoinColumn(name = "OtherEntityForeignKey")}) 

注意 - 这是多对多的映射关系正常化的一般方式。你可以得到一个很好的答案,如果你可以更新表结构的问题..