需要从实体管理器获得多个结果

时间:2012-07-30 19:00:34

标签: java jpa openjpa

我一直试图在最后一刻想出这个。与所有询问如何仅从JPA查询获得一个结果的问题形成对比,我需要更多而不是一个结果 - 我需要所有这些。我最终调用了实体管理器的find()方法,但它没有得到所有嵌套结果。

'家长'班

@Entity
@Table(name = "LANGUAGE")  
public class LanguageData extends PersistedAuditedData<Long> {

@Id
@Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "ISO6391ALPHA2CODE")
private String iso6391Alpha2Code;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "languageData")
@MapKeyColumn(name = "LANGUAGE_ID")
private Map<Long, LanguageDataLocalization> localizations;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "localizationLanguage")
@MapKeyColumn(name = "LANGUAGE_LOCALIZATION_ID")
private Map<Long, LanguageDataLocalization> languagesLocalized;

/**
 * Private no-arg constructor for reflection-based 
     * construction inside JPA providers.
 */
@SuppressWarnings("unused")
private LanguageData() {
    // Fields initialized by JPA.
}

    // Plus getters for the fields.

}

'儿童'课程

@Entity
@Table(name = "LANGUAGE_LOCALIZATION")
public class LanguageDataLocalization extends PersistedAuditedData<LanguageLocalizationKey>{

@EmbeddedId
private LanguageLocalizationKey id;

@Column(name = "REFERENCE_NAME")
private String name;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "LANGUAGE_ID", insertable = false, updatable = false)
private LanguageData languageData;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "LANGUAGE_LOCALIZATION_ID", insertable = false, updatable = false)
private LanguageData localizationLanguage;

/**
 * Private no-arg constructor for reflection-based JPA provider instantiation.
 */
@SuppressWarnings("unused")
private LanguageDataLocalization() {
    // Fields initialized by JPA.
}

    // Plus getters for fields.
}

'儿童'课程的关键。

@Embeddable
public class LanguageLocalizationKey {

@Column(name = "LANGUAGE_ID")
private Long languageId;

@Column(name = "LANGUAGE_LOCALIZATION_ID")
private Long languageLocalizationId;

/**
 * No-arg constructor, for use by JPA provider implementation.
 * <h1>DO NOT USE!</h1>
 * <p>Ideally, this should be <code>private</code>, 
     * however OpenJPA doesn't appear to be allowing that at the moment   
 * (unsure of cause).  This constructor does not initialize any data.</p>
 */
@SuppressWarnings("unused")
public LanguageLocalizationKey() {
    // Field initialization performed by JPA provider.
}

    // Plus getters
}

如此使用:

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
private Collection<LanguageDataLocalization> getLocalizationsById(final Long id, final Collection<String> localeCodes) {
    try {
        if (localeCodes == null || localeCodes.isEmpty()) {
            final LanguageData data = entityManager.find(LanguageData.class, id);
            if (data == null) {
                return Collections.emptyList();
            } else {
                return data.getlocalizations().values();
            }
        } else {
            List<LanguageDataLocalization> results = entityManager.createNamedQuery("FIND_LANGUAGE_BY_ID", LanguageDataLocalization.class)
                                                                    .setParameter("iso6391Alpha2Codes", localeCodes)
                                                                    .setParameter("languageId", id)
                                                                    .getResultList();
            return results;
        }
    } catch (NoResultException e) {
        // TODO: add logging
        return Collections.emptyList();
    }
}

named-queries.xml定义如下:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence/orm" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
                    http://java.sun.com/xml/ns/persistence/orm_1_0.xsd ">

<named-query name="FIND_LANGUAGE_BY_ID">
    <query>
        SELECT localized 
        FROM LanguageDataLocalization localized
        JOIN localized.localizationLanguage local
        WHERE localized.id.languageId = :languageId
        AND local.iso6391Alpha2Code IN :iso6391Alpha2Codes
    </query>
</named-query>
</entity-mappings>

LANGUAGE数据(Derby内存数据库,非常肯定并不重要):

ID,  ISO6391ALPHA2CODE
123, en
137, fr

LANGUAGE_LOCALIZATION数据

LANGUAGE_ID, LANGUAGE_LOCALIZATION_ID, REFERENCE_NAME
123,         123,                      English
123,         137,                      anglais

实际问题是当查询没有任何区域设置数据(localeCodes为空或空)时,data.getLocalizations().values()之后entityManager.find()只返回一个列表本地语言名称数据的一个(法语数据,但我假设SQL'随机')。我 am 能够获得两个本地化,如果我明确地查询它们(单独或一起),所以我知道数据的那里,并且JPQL查询有效。

如果没有查询特定的本地化,我该怎么做才能让它返回(所有,当我有超过2种语言的本地化数据时)本地化?


实际查询似乎是这样(删除了一些结果列):

SELECT t0.LANGUAGE_ID, t0.LANGUAGE_LOCALIZATION_ID, 
       t1.ISO6391ALPHA2CODE, 
       t0.REFERENCE_NAME 
FROM LANGUAGE_LOCALIZATION t0 
LEFT OUTER JOIN LANGUAGE t1 
ON t0.LANGUAGE_LOCALIZATION_ID = t1.id 
WHERE t0.LANGUAGE_ID = ? [params=?]

这似乎不会以任何方式限制行数。 (to.LANGUAGE_ID匹配多行)。特别是因为,在同一个数据集中,以下内容获取两个结果行(再次删除了一些结果列):

SELECT t0.LANGUAGE_ID, t0.LANGUAGE_LOCALIZATION_ID, 
       t2.id, t2.ISO6391ALPHA2CODE, 
       t3.id, t3.ISO6391ALPHA2CODE, 
       t0.REFERENCE_NAME 
FROM LANGUAGE_LOCALIZATION t0 
INNER JOIN LANGUAGE t1 
ON t0.LANGUAGE_LOCALIZATION_ID = t1.id 
LEFT OUTER JOIN LANGUAGE t2 
ON t0.LANGUAGE_ID = t2.id 
LEFT OUTER JOIN LANGUAGE t3 
ON t0.LANGUAGE_LOCALIZATION_ID = t3.id 
WHERE (t0.LANGUAGE_ID = ? AND t1.ISO6391ALPHA2CODE IN (?, ?)) [params=?, ?, ?]

(这提出了为什么它同时包含t1 t3的问题,但目前这是一个较少关注的问题。)

2 个答案:

答案 0 :(得分:0)

你能启用SQL生成调试,以便我们可以看到sql代码到底是什么吗?

在休眠中它的东西如下:     <property name = "hibernate.show_sql" value = "true" />

答案 1 :(得分:0)

我终于弄清楚出了什么问题 -
我已将一对多映射映射到错误列的键。 LanguageData的定义需要更改为:

@Entity
@Table(name = "LANGUAGE")
public class LanguageData extends PersistedAuditedData<Long> {

@Id
@Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "ISO6391ALPHA2CODE")
private String iso6391Alpha2Code;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "languageData")
@MapKeyColumn(name = "LANGUAGE_LOCALIZATION_ID")
private Map<Long, LanguageDataLocalization> localizations;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "localizationLanguage")
@MapKeyColumn(name = "LANGUAGE_ID")
private Map<Long, LanguageDataLocalization> languagesLocalized;

/**
 * Private no-arg constructor for reflection-based construction inside JPA providers.
 */
@SuppressWarnings("unused")
private LanguageData() {
    // Fields initialized by JPA.
}

// Plus getters for fields
}

我对地图的概念应该是正确的,但我没有考虑如何键入它们(从其他列开始)。