我一直试图在最后一刻想出这个。与所有询问如何仅从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
的问题,但目前这是一个较少关注的问题。)
答案 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
}
我对地图的概念应该是正确的,但我没有考虑如何键入它们(从其他列开始)。