2

私はここしばらくの間、これを理解しようとしてきました。JPAクエリから1つの結果のみを取得する方法を尋ねるこれらすべての質問とは完全に対照的に、複数の結果が必要です。すべての結果が必要です。エンティティマネージャーの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( nullまたは空)でクエリを実行すると、ローカライズされた言語名データの1(フランス語のデータですが、SQL'ランダム')のリストが返されることdata.getLocalizations().values()ですentityManager.find()。明示的に(単独または一緒に)クエリを実行すると、両方のローカリゼーションを取得できるため、データがそこにあり、 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

私はついに何が間違っているのかを理解しました-
間違った列をキーオフするために1対多のマップをマップしました。の定義を次の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 に答える