У меня возникают трудности с достижением соответствующего отображения объекта, содержащего карту примитивов (Map).Результирующий SQL - это не то, что я ожидаю (левое внешнее соединение), и в результате получается, что при получении списка указанных сущностей сущности, которые должны быть уникальными, дублируются в результате.
Вот сущность (сокращенно):
@Entity(name = "ZPrincipal")
@Table(name = "users")
public class ZPrincipal implements Principal, Serializable {
@Id
@Column(name = "username")
private String username;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "user_metadata", joinColumns = { @JoinColumn(name = "username") })
@MapKeyColumn(name = "meta_key")
@Column(name = "meta_value", nullable = false)
private Map<String, String> metadata;
}
Как видите, существует пользовательский класс (ZPrincipal), который содержит карту.Мои таблицы выглядят так (опять же, сокращая некоторые поля от «пользователей», таких как электронная почта, пароль и т. Д.):
CREATE TABLE users (
username VARCHAR(60) NOT NULL,
PRIMARY KEY (username)
);
CREATE TABLE user_metadata (
username VARCHAR(60) NOT NULL,
meta_key VARCHAR(255) NOT NULL,
meta_value VARCHAR(1024) NOT NULL,
CONSTRAINT user_meta_fk FOREIGN KEY (username) REFERENCES users (username),
PRIMARY KEY (username, meta_key)
);
Некоторые примеры содержимого:
Таблица пользователей:
|username |
+---------+
|admin |
|brett |
+---------+
Таблица метаданных:
|username |meta_key |meta_value |
+---------+----------+------------+
|brett |key1 |value1 |
|brett |key2 |value2 |
+---------+----------+------------+
Используя приведенное выше отображение, когда я использую Hibernate для получения списка ZPrincipals, например так:
Criteria criteria = session.createCriteria(ZPrincipal.class);
List<ZPrincipal> list = criteria.list();
Hibernate запускает следующий запрос:
select this_.username as username9_1_,
metadata2_.username as username9_3_,
metadata2_.meta_value as meta2_3_,
metadata2_.meta_key as meta3_3_
from users this_
left outer join user_metadata metadata2_ on this_.username=metadata2_.username
В результате возвращаются строки:
|username9_1_ |username9_3_ |meta2_3_ |meta3_3_ |
+--------------+--------------+----------+----------+
|admin |null |null |null |
|brett |brett |key1 |value1 |
|brett |brett |key2 |value2 |
+--------------+--------------+----------+----------+
В результате получается список пользователей, содержащий 3 сущности (то есть "проблема"), "admin "объект пользователя и два" бретта "объекта пользователя (идентичные).Оба «бретт» экземпляра действительно содержат правильно заполненную карту.Для тех, кому интересно, класс ZPrincipal делает переопределение equals (), которое обеспечивает сравнение на основе имени пользователя (такое же, как первичный ключ), и переопределяет hashCode (), также хэширующее имя пользователя.
Наш магазинработает от «схемы сначала», и схема кажется «правильной» в смысле базы данных.Возможно, эту проблему можно решить с помощью промежуточной таблицы сопоставления и сгенерированных идентификаторов в таблице user_metadata, но из чтения доступной документации JPA и Hibernate (http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection) кажется, что сопоставление набора примитивных элементов с использованием только двух таблицдолжно быть возможно.
Чего не хватает в отображении? Или это ошибка в Hibernate? И если да, кто-нибудь может придумать обходной путь сопоставления? Я немного обшарил аннотациинет радости.