OneToOne JPA / Hibernate eager loading cause N+1 select

Posted by Alexandre Lavoie on Stack Overflow See other posts from Stack Overflow or by Alexandre Lavoie
Published on 2014-06-06T07:36:28Z Indexed on 2014/06/10 9:25 UTC
Read the original article Hit count: 319

Filed under:
|
|

I created a method to have multilingual text on different objects without creating field for each languages or tables for each objects types.

Now the only problem I've got is N+1 select queries when doing a simple loading.

Tables schema :

CREATE TABLE `testentities` (
  `keyTestEntity` int(11) NOT NULL,
  `keyMultilingualText` int(11) NOT NULL,
  PRIMARY KEY  (`keyTestEntity`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

CREATE TABLE `common_multilingualtexts` (
  `keyMultilingualText` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`keyMultilingualText`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

CREATE TABLE `common_multilingualtexts_values` (
  `languageCode` varchar(5) NOT NULL,
  `keyMultilingualText` int(11) NOT NULL,
  `value` text,
  PRIMARY KEY  (`languageCode`,`keyMultilingualText`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

MultilingualText.java

@Entity
@Table(name = "common_multilingualtexts")
public class MultilingualText implements Serializable
{
    private Integer m_iKeyMultilingualText;
    private Map<String, String> m_lValues = new HashMap<String, String>();

    public void setKeyMultilingualText(Integer p_iKeyMultilingualText)
    {
        m_iKeyMultilingualText = p_iKeyMultilingualText;
    }

    @Id
    @GeneratedValue
    @Column(name = "keyMultilingualText")
    public Integer getKeyMultilingualText()
    {
        return m_iKeyMultilingualText;
    }

    public void setValues(Map<String, String> p_lValues)
    {
        m_lValues = p_lValues;
    }

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "common_multilingualtexts_values", joinColumns = @JoinColumn(name = "keyMultilingualText"))
    @MapKeyColumn(name = "languageCode")
    @Column(name = "value")
    public Map<String, String> getValues()
    {
        return m_lValues;
    }

    public void put(String p_sLanguageCode, String p_sValue)
    {
        m_lValues.put(p_sLanguageCode,p_sValue);
    }

    public String get(String p_sLanguageCode)
    {
        if(m_lValues.containsKey(p_sLanguageCode))
        {
            return m_lValues.get(p_sLanguageCode);
        }

        return null;
    }
}

And it is used like this on a object (having a foreign key to the multilingual text) :

@Entity
@Table(name = "testentities")
public class TestEntity implements Serializable
{
    private Integer m_iKeyEntity;
    private MultilingualText m_oText;

    public void setKeyEntity(Integer p_iKeyEntity)
    {
        m_iKeyEntity = p_iKeyEntity;
    }

    @Id
    @GeneratedValue
    @Column(name = "keyEntity")
    public Integer getKeyEntity()
    {
        return m_iKeyEntity;
    }


    public void setText(MultilingualText p_oText)
    {
        m_oText = p_oText;
    }

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "keyText")
    public MultilingualText getText()
    {
        return m_oText;
    }
}

Now, when doing a simple HQL query : from TestEntity, I get a query selecting TestEntity's and one query for each MultilingualText that need to be loaded on each TestEntity. I've searched a lot and found absolutely no solutions. I have tested :

  • @Fetch(FetchType.JOIN)
  • optional = false
  • @ManyToOne instead of @OneToOne

Now I am out of idea!

© Stack Overflow or respective owner

Related posts about hibernate

Related posts about jpa