У меня следующие занятия:
public abstract class Entity<T> implements Serializable {
protected long id;
protected Map<Language,EntityMetaData> metaData;
...
public class Service extends Entity<Long> implements Serializable {
protected String name;
Отображения XML:
<class name="Service" table="SERVICES" schema="EDRIVE" dynamic-update="false" dynamic-insert="true" batch-size="30">
<meta attribute="class-description">
This class contains definitions of relations between entities
</meta>
<id name="id" type="long" column="id">
<generator class="identity" />
</id>
<map name="metaData" table="ServiceMetaData">
<key column="serviceid"/>
<map-key-many-to-many column="languageId" class="com.core.domain.Language"/>
<one-to-many entity-name="serviceMetaData"/>
</map>
</class>
<class name="EntityMetaData" entity-name="serviceMetaData" table="SERVICESMETADATA" lazy="false">
<id name="id" type="long" column="id" access="field">
<generator class="identity" />
</id>
<property name="name" column="name" type="string" length="256" />
<property name="description" column="description" type="string" length="512"/>
</class>
Я хочу загрузить serviceMetadata только для определенного языка, например, ru, en, uk и т. Д.:
Service serviceEntity = (Service) databaseUtilities
.getSession()
.createQuery("FROM Service s"
+ " JOIN FETCH s.metaData m"
+ " WHERE s.id = :id AND m.language = :language")
.setParameter("id", serviceId)
.setParameter("language", language)
.uniqueResult();
Где serviceId - длинный, язык является экземпляром класса Language.
Когда я пробую описанный выше подход, я получаю следующее исключение:
org.hibernate.QueryException: не удалось разрешить свойство: язык: serviceMetaData [FROM com.core.domain.service.Service s JOIN FETCH s.metaData m WHERE s.id =: id AND m.language =: language]
В противном случае:
Service serviceEntity = (Service) databaseUtilities
.getSession()
.createQuery("FROM Service s"
+ " WHERE s.id = :id AND s.metaData['language'] = :language")
.setParameter("id", serviceId)
.setParameter("language", language)
.uniqueResult();
Исключение
org.postgresql.util.PSQLException: ОШИБКА: недопустимый синтаксис ввода для целого типа: "язык" Позиция: 235
И CROSS JOIN!
Хорошо, удалили все условия, только служба + все метаданные принадлежат ему, чтобы увидеть, как он построен. Вот сериализованный набор результатов JSON:
"service": {
"id": 5,
"entityType": null,
"entityKey": null,
"metaData": {
"com.core.domain.Language@57d41bfc": {
"id": 2145,
"entityType": null,
"entityKey": null,
"metaData": null,
"miscMetaData": null,
"name": "Заправка топливом",
"description": null
},
"com.core.domain.Language@99ca0b20": {
"id": 2144,
"entityType": null,
"entityKey": null,
"metaData": null,
"miscMetaData": null,
"name": "Fueling",
"description": null
}
},
"miscMetaData": null,
"name": "FUELING",
"serviceType": {
"id": 23,
"entityType": null,
"entityKey": null,
"metaData": null,
"miscMetaData": null,
"value": "RECURRENT"
}
}
Как вы можете видеть здесь, метаданные состоят из двух объектов (на самом деле это PersistentMap с ключом = Language).
Итак, возникает вопрос: как получить конкретное значение карты по языку с помощью Hibernate?
1 ответ
JPA требует, чтобы состояние управляемых объектов и базы данных было синхронизировано в конце транзакции, поэтому выборка только частичной коллекции объекта по существу удаляла бы невыбранные элементы, поэтому JPA не позволяет этого. Однако вы можете сделать это с помощью Hibernate, но я бы не рекомендовал его, потому что это может привести к удалению.
Итак, чтобы получить то, что вы хотите, вам нужно написать запрос HQL и получить данные в DTO. В запросе вы выбираете все нужные поля и можете определить условие соединения по своему усмотрению. Примерно так:
SELECT s.id, s.name, m.id, m.name
FROM Service s
LEFT JOIN s.metadata m ON KEY(m) = 'en'
Я думаю, что это идеальный вариант использования для Blaze-Persistence Entity Views .
Я создал библиотеку, чтобы обеспечить простое сопоставление между моделями JPA и пользовательским интерфейсом или моделями, определенными абстрактным классом, что-то вроде Spring Data Projection на стероидах. Идея состоит в том, что вы определяете свою целевую структуру (модель домена) так, как вам нравится, и сопоставляете атрибуты (геттеры) через выражения JPQL с моделью сущности.
Вот пример кода для исходного итератора:
@EntityView(Service.class)
public interface ServiceDto {
@IdMapping
Long getId();
String getName();
@Mapping("metadata['en']")
LanguageDto getLanguage();
@EntityView(EntityMetaData.class)
interface LanguageDto {
@IdMapping
Long getId();
String getName();
}
// Other mappings
}
Запрос - это применение представления сущности к запросу, простейшим из которого является запрос по идентификатору.
ServiceDto a = entityViewManager.find(entityManager, ServiceDto.class, id);
Интеграция Spring Data позволяет использовать ее почти как Spring Data Projection: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Похожие вопросы
Новые вопросы
hibernate
Hibernate - это библиотека объектно-реляционного отображения (ORM) для языка Java, позволяющая разработчикам использовать модели доменов в стиле POJO в своих приложениях способами, выходящими далеко за пределы объектно-реляционного отображения.