使用 Spring Data JPA 在 BLOB 上构建 JPQL
Build a JPQL on a BLOB with Spring Data JPA
我正在使用一个外部服务,该服务发送到我的应用程序中的一个端点,我在其中有一个 @RequestBody CalloutRequest calloutRequest
,我将请求正文映射到 Class CalloutRequest
.
作为 CalloutRequest 的一部分,有一个名为 userAttributes
的字段,在我的 class 中看起来像这样:
@Lob
private HashMap<String, List<String>> userAttributes;
我用 @Lob
对它进行了注释,因为我没有 class 可以映射到它,因为它的性质相当复杂。因此这个HashMap。 JSON 格式时 userAttributes 的示例:
"userAttributes": {
"lastName": [
"Guy"
],
"ExternalId": [
"d9a59407-2bca-46aa-8641-3350fd95bcd1"
],
"distinguishedName": [
"CN=t2-contractor9,DC=company,DC=com"
],
"employeeID": [],
"userName": [
"t2-contractor9@company.com"
],
"groupNames": [
"ALL USERS",
"T2-Contractor@company.com"
],
"firstName": [
"T2-Contractor"
],
"UserStore": [],
"phone": [],
"domain": [
"company.com"
],
"disabled": [
"false"
],
"email": [
"t2-contractor9@company.com"
]
}
我的挑战是我想为特定用户名构建查询 - userAttributes.userName
- 但考虑到这是作为 BLOB 存储的事实,我无法弄清楚如何 - 或者如果可能的话 -写这样一个查询。
现在我只是在使用 Spring Data JPA 及其存储库实现,但我想知道这是否是我可以通过自定义 @Query
或使用 querydsl 实现的?
我的理解是否正确,如果我能想出一种方法将上面的 HashMap 映射到实际的 class 我可以使用 serialise/de-serialise 并在 CalloutRequest 和这个新的之间建立映射class 我可以构建一个 JPQL 查询,使用连接来实现我想要的吗?
在这里利用 AttributeConverter
实现怎么样:
public class YourEntity {
// ...
@ElementCollection
@Convert(name = "value", converter = StringListToStringConverter.class)
private Map<String, List<String>> userAttributes;
}
StringListToStringConverter
的简单实现可能是:
public class StringListToStringConverter
implements AttributeConverter<List<String>, String> {
private static final String DELIMITER = "|";
@Override
public String converToDatabaseColumn(List<String> attributes) {
if ( attributes == null || attributes.isEmpty() ) {
return null;
}
StringBuilder sb = new StringBuilder();
for ( Iterator<String> i = attribtues.iterator(); i.hasNext(); ) {
sb.append( i.next() );
if ( i.hasNext() ) {
sb.append( DELIMITER );
}
}
return sb.toString();
}
@Override
public List<String> convertToEntityAttribute(String data) {
if ( data == null ) {
return new ArrayList<String>();
}
List<String> values = Arrays.asList( StringHelper.split( DELIMITER, data ) );
return new ArrayList<String>( values );
}
}
您显然必须处理输入流包含您的 DELIMITER
排序值的情况,但它可能会起作用,具体取决于您的用例。
我相信您可以使用 HQL 编写查询,例如:
SELECT e FROM YourEntity e JOIN e.userAttributes a
WHERE VALUE(a) = :mapValue
如果您使用 Hibernate 作为 JPA 实现并使用 PostgreSQL 作为数据库,请查看 hibernate-native-json 项目:
例子
您可以序列化 class 或 Map(在任何情况下都需要一个更动态的字段)。
@Entity
public class MyClass {
@Type(type = "com.marvinformatics.hibernate.json.JsonListUserType")
@Target(Label.class)
private List<Label> labels = new ArrayList<Label>();
@Type(type = "com.marvinformatics.hibernate.json.JsonUserType")
private Map<String, String> extra;
}
这允许像这样的 HQL 查询:
select
json_text(i.label, 'value')
from
Item i
where
json_text(i.label, 'lang') = :lang
祝你好运!
我正在使用一个外部服务,该服务发送到我的应用程序中的一个端点,我在其中有一个 @RequestBody CalloutRequest calloutRequest
,我将请求正文映射到 Class CalloutRequest
.
作为 CalloutRequest 的一部分,有一个名为 userAttributes
的字段,在我的 class 中看起来像这样:
@Lob
private HashMap<String, List<String>> userAttributes;
我用 @Lob
对它进行了注释,因为我没有 class 可以映射到它,因为它的性质相当复杂。因此这个HashMap。 JSON 格式时 userAttributes 的示例:
"userAttributes": {
"lastName": [
"Guy"
],
"ExternalId": [
"d9a59407-2bca-46aa-8641-3350fd95bcd1"
],
"distinguishedName": [
"CN=t2-contractor9,DC=company,DC=com"
],
"employeeID": [],
"userName": [
"t2-contractor9@company.com"
],
"groupNames": [
"ALL USERS",
"T2-Contractor@company.com"
],
"firstName": [
"T2-Contractor"
],
"UserStore": [],
"phone": [],
"domain": [
"company.com"
],
"disabled": [
"false"
],
"email": [
"t2-contractor9@company.com"
]
}
我的挑战是我想为特定用户名构建查询 - userAttributes.userName
- 但考虑到这是作为 BLOB 存储的事实,我无法弄清楚如何 - 或者如果可能的话 -写这样一个查询。
现在我只是在使用 Spring Data JPA 及其存储库实现,但我想知道这是否是我可以通过自定义 @Query
或使用 querydsl 实现的?
我的理解是否正确,如果我能想出一种方法将上面的 HashMap 映射到实际的 class 我可以使用 serialise/de-serialise 并在 CalloutRequest 和这个新的之间建立映射class 我可以构建一个 JPQL 查询,使用连接来实现我想要的吗?
在这里利用 AttributeConverter
实现怎么样:
public class YourEntity {
// ...
@ElementCollection
@Convert(name = "value", converter = StringListToStringConverter.class)
private Map<String, List<String>> userAttributes;
}
StringListToStringConverter
的简单实现可能是:
public class StringListToStringConverter
implements AttributeConverter<List<String>, String> {
private static final String DELIMITER = "|";
@Override
public String converToDatabaseColumn(List<String> attributes) {
if ( attributes == null || attributes.isEmpty() ) {
return null;
}
StringBuilder sb = new StringBuilder();
for ( Iterator<String> i = attribtues.iterator(); i.hasNext(); ) {
sb.append( i.next() );
if ( i.hasNext() ) {
sb.append( DELIMITER );
}
}
return sb.toString();
}
@Override
public List<String> convertToEntityAttribute(String data) {
if ( data == null ) {
return new ArrayList<String>();
}
List<String> values = Arrays.asList( StringHelper.split( DELIMITER, data ) );
return new ArrayList<String>( values );
}
}
您显然必须处理输入流包含您的 DELIMITER
排序值的情况,但它可能会起作用,具体取决于您的用例。
我相信您可以使用 HQL 编写查询,例如:
SELECT e FROM YourEntity e JOIN e.userAttributes a
WHERE VALUE(a) = :mapValue
如果您使用 Hibernate 作为 JPA 实现并使用 PostgreSQL 作为数据库,请查看 hibernate-native-json 项目:
例子
您可以序列化 class 或 Map(在任何情况下都需要一个更动态的字段)。
@Entity
public class MyClass {
@Type(type = "com.marvinformatics.hibernate.json.JsonListUserType")
@Target(Label.class)
private List<Label> labels = new ArrayList<Label>();
@Type(type = "com.marvinformatics.hibernate.json.JsonUserType")
private Map<String, String> extra;
}
这允许像这样的 HQL 查询:
select
json_text(i.label, 'value')
from
Item i
where
json_text(i.label, 'lang') = :lang
祝你好运!