hibernate - 休眠查询:通过映射键加入
问题描述
我有以下课程:
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 是 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
并交叉加入!
好吧,去掉任何条件,只有service+所有元数据属于它,看它是如何构造的。这是一个序列化为 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"
}
}
正如您在此处看到的,元数据由两个对象组成(实际上是带有 key = Language 的 PersistentMap)。
所以,问题是:如何使用 Hibernate 通过语言检索特定的地图值?
解决方案
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 Projections on steroids。这个想法是您以您喜欢的方式定义您的目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:
@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
}
查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。
ServiceDto a = entityViewManager.find(entityManager, ServiceDto.class, id);
Spring Data 集成允许您几乎像 Spring Data Projections 一样使用它:https ://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
推荐阅读
- azure - “无法订阅成本管理数据”AZURE 成本使用 API
- javascript - 用户输入未正确拆分,提供输入时不会执行实时搜索功能
- android - Android Camera2 在某些设备上捕获旋转 90 度
- python - 使用 aiohttp 和 python 3.8 来自服务器的空回复
- python - 基于距离的熊猫样本
- git - 合并多个分支后如何重新安排 git release 分支?
- javascript - React Textfield onChange 捕获之前的 event.target.value
- xerces2-j - 如何配置 xerces 自定义 xincludehandler
- javascript - 在不更改 js 文件的情况下将用户带到其他页面
- websocket - Websocket:如何只接收来自连接的最新消息?