2017-01-31 32 views
0

Im работает с внешней службой, которая отправляет POST на конечную точку в моем приложении, где у меня есть @RequestBody CalloutRequest calloutRequest, где я сопоставляю тело запроса с классом CalloutRequest.Создайте JPQL на BLOB с данными Spring. JPA

В рамках этого CalloutRequest это поле называется userAttributes, который выглядит, как это в моем классе:

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

Я его аннотированный остроумие @Lob, потому что у меня нет класса, который я могу сопоставить его из-за его довольно сложный характер. Поэтому это HashMap. Пример того, что userAttributes выглядит следующим образом, когда в формате JSON:

"userAttributes": { 
    "lastName": [ 
     "Guy" 
    ], 
    "ExternalId": [ 
     "d9a59407-2bca-46aa-8641-3350fd95bcd1" 
    ], 
    "distinguishedName": [ 
     "CN=t2-contractor9,DC=company,DC=com" 
    ], 
    "employeeID": [], 
    "userName": [ 
     "[email protected]" 
    ], 
    "groupNames": [ 
     "ALL USERS", 
     "[email protected]" 
    ], 
    "firstName": [ 
     "T2-Contractor" 
    ], 
    "UserStore": [], 
    "phone": [], 
    "domain": [ 
     "company.com" 
    ], 
    "disabled": [ 
     "false" 
    ], 
    "email": [ 
     "[email protected]" 
    ] 
    } 

Моя задача состоит в том, что я хотел бы создать запрос для конкретного пользователя - userAttributes.userName - но, учитывая тот факт, что это хранится в виде двоичных объектов I не может понять, как - или, если это вообще возможно - написать такой запрос.
Прямо сейчас я просто использую Spring Data JPA и это реализация репозитория, но мне интересно, можно ли это сделать с помощью настраиваемого @Query или, возможно, с помощью querydsl?

Я правильно понимаю, что если бы я мог найти способ сопоставить вышеуказанный HashMap с фактическим классом, который мог бы использовать для сериализации/де-сериализации и иметь сопоставление между CalloutRequest и этим новым классом, я мог бы построить JPQL-запрос, который будет использовать соединение для достижения того, что мне нужно?

ответ

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 
+0

Это похоже на работу очень хорошо! Я могу реализовать объект с помощью '@ ElementCollection' и' @ Convert'. Однако я не могу получить запрос на работу, скорее всего, потому что я не полностью понимаю, что на самом деле делает 'StringListToStringConverter'. Я думал, что могу просто передать String для i.e.ername в метод запроса, но это не удается: «Значение параметра не соответствует ожидаемому типу [java.util.List] "- что именно мне нужно предоставить, чтобы конвертер мог понять мой метод? –

+0

Прошу прощения, я не тестировал это, поэтому, возможно, вам придется подстроить запрос как« WHERE VALUE (a) IN (: mapValues) 'и указать именованный параметр как' Список '? – Naros

+0

Это дает мне: ' java.lang.ClassCastException: java.lang.String не может быть переведен в java.util.List' из метода 'convertToDatabaseColumn'. My '@ Query' аннотированный метод выглядит в моем хранилище: ' CalloutRequest findWhereUser (@param ("Username") Список Username); ' –

0

Если вы используете Hibernate в качестве реализации JPA и PostgreSQL в качестве БД взглянуть на 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 

Удачи!

+0

К сожалению, я использую базу данных на основе файлов H2 (небольшой проект), но я обязательно запомню это для будущих проектов! Благодарю. –