在过去的一段时间里,我一直在努力解决这个问题。与所有那些询问如何仅从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
的问题,但目前这是一个不太关心的问题。)