2

在过去的一段时间里,我一直在努力解决这个问题。与所有那些询问如何仅从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 '随机')。如果我明确地查询它们(单独或一起),能够获得两种本地化,所以我知道数据在那里,并且 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的问题,但目前这是一个不太关心的问题。)

4

2 回答 2

0

你能启用 SQL 生成调试,以便我们可以看到真正的 sql 代码吗?

在休眠状态下,它类似于: <property name = "hibernate.show_sql" value = "true" />

于 2012-07-31T09:09:20.627 回答
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
}

我的地图应该包含的概念是正确的,但我没有考虑它们应该如何键控(离开另一列)。

于 2012-08-03T19:48:46.910 回答