使用Spring Data JPA在BLOB上构建JPQL

时间:2017-01-31 20:32:50

标签: hibernate jpa spring-data-jpa jpql querydsl

我正在使用一个外部服务,该服务POST到我的应用程序中的端点,我有一个@RequestBody CalloutRequest calloutRequest,我将请求正文映射到类CalloutRequest

作为CalloutRequest的一部分,一个名为userAttributes的字段在我的班级中看起来像这样:

@Lob    
private HashMap<String, List<String>> userAttributes;

我有一个带注释的机智@Lob,因为我没有可以映射它的课程,因为它相当复杂。因此这个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映射到一个实际的类我可以用来序列化/反序列化并在CalloutRequest和这个新类之间有一个映射我可以构建一个JPQL查询将使用连接来实现我所追求的目标?

2 个答案:

答案 0 :(得分:0)

如何在此处利用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

答案 1 :(得分:0)

如果你使用Hibernate作为JPA实现而PostgreSQL作为DB看看hibernate-native-json项目:

示例

您可以序列化类或地图(在任何情况下都需要更动态的字段)。

@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
祝你好运!