我有一個JPA物體(Terminal),它使用一個AttributeConverter將資料庫字串轉換成一個物件串列(ProgrmRegistration)。該轉換器只是使用JSON ObjectMapper來將JSON字串轉化為POJO物件。
Entity Object
@Entity
@Data
public class Terminal {
@Id[/span
private String terminalId;
@NotEmpty
@Convert(verter = ProgramRegistrationConverter.class)
private List<ProgramRegistration> programRegistrations;
@Data(轉換器 = ProgramRegistrationConverter.class)
public static class ProgramRegistration {
private String program;
private boolean online;
}
終端使用以下JPA AttributeConverter來將Objects從JSON中序列化,并將其序列化為JSON
。JPA AttributeConverter
public class ProgramRegistrationConverter implements AttributeConverter< List<終端。 ProgramRegistration>, String> {。
private final ObjectMapper objectsMapper;
private final CollectionType programRegistrationCollectionType;
public ProgramRegistrationConverter() {
this.objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY)。
this.programRegistrationCollectionType =
objectMapper.getTypeFactory().constructCollectionType(List.class, Terminal.ProgramRegistration.class) 。
}
@Override; }
public String convertToDatabaseColumn(List<Terminal.ProgramRegistration> attribute) {
if (attribute == null) {
return null;
}
String json = null;
try {
json = objectMapper.writeValueAsString(attribute)。
} catch (final JsonProcessingException e) {
LOG.error("JSON writing error", e);
}
return json;
}
@Override
public List<Terminal.ProgramRegistration> convertToEntityAttribute(String dbData) {
if (dbData == null) {
return Collections.emptyList()。
}
List<Terminal.ProgramRegistration> list = null;
try {
list = objectMapper.readValue(dbData, programRegistrationCollectionType)。
} catch (final IOException e) {
LOG.error("JSON read error", e);
}
return串列。
}
}
我正在使用Spring Boot和一個JPARepository從資料庫中獲取一個終端結果頁面。 為了過濾結果,我使用一個BooleanExpression作為謂詞。對于物體上的所有過濾值來說,它運行良好,但從 JSON 字串轉換而來的物件串列不允許我輕松撰寫一個運算式來過濾串列中的物件。
試圖使用QueryDSL過濾物體物件的REST API
@GetMapping(path = "/filtered/page"/span>, produces = MediaType. APPLICATION_JSON_VALUE)
public Page<Terminal> findFilteredWithPage()。
@RequestParam(required = false) String terminalId。
@RequestParam(required = false) String programName,
@PageableDefault(size = 20) @SortDefault.SortDefaults({ @SortDefault(sort = "terminalId") }) Pageable p) {
BooleanBuilder builder = new BooleanBuilder() 。
if (StringUtils.isNotBlank(terminalId))
builder.and(QTerminal.terminal.terminalId.upper()
.contains(StringUtils.upperCase(terminalId)) )。
// TODO:弄清楚如何使用QueryDsl來獲取轉換后的List作為謂詞。
//下面用于查找programRegistrations的代碼不允許呼叫any(),
//期待一個CollectionExpression或SubqueryExpression用于呼叫eqAny()或in()。
if (StringUtils.isNotBlank(program))
builder.and(QTerminal.terminal。 programRegistrations.any().name()
.contains(StringUtils.upperCase(programName))。
return terminalRepository.findAll(builder.getValue(), p) 。
}
我想獲得任何擁有ProgramRegistration物件的終端,該物件的程式名稱與傳入REST服務的引數相同。
我一直試圖讓 CollectionExpression 或 SubQueryExpression 作業,但沒有成功,因為它們似乎都想在兩個物體物件之間執行連接。我不知道如何創建路徑和查詢,以便它能夠遍歷programRegistrations,檢查 "program "欄位是否匹配。我沒有一個QProgamRegistration物件來連接,因為它只是一個POJO的串列。
我怎樣才能讓謂詞只匹配具有我正在搜索的名稱的程式的終端?
這是不作業的行:
builder.and(QTerminal. terminal.programRegistrations.any().name() .contains(StringUtils.upperCase(programName)));
uj5u.com熱心網友回復:
AttributeConverters在Querydsl中存在問題,因為它們在JPQL--JPA的查詢語言--中存在問題。不清楚屬性的底層查詢型別是什么,也不清楚引數是否應該是該查詢型別的基本型別,或者應該使用轉換來轉換。這樣的轉換雖然看起來合乎邏輯,但在JPA規范中卻沒有定義。因此,需要使用查詢型別的基本型別,這導致了新的困難,因為Querydsl不能知道它需要的型別。它只知道該屬性的 Java 型別。
一個解決方法是通過用@QueryType(PropertyType.STRING)注釋該欄位來強制該欄位變成一個StringPath。雖然這解決了一些查詢的問題,但在其他情況下你會遇到不同的問題。欲了解更多資訊,請參閱這個執行緒。
uj5u.com熱心網友回復:
盡管以下所需的QueryDsl看起來應該可以作業
QTerminal.terminal。 programRegistrations.any().name().contains(programName)。
在現實中,JPA永遠無法將其轉換為在SQL方面有意義的東西。JPA唯一可以將其轉換為的SQL陳述句如下:
在現實中,JPA永遠無法將其轉換為有意義的SQL陳述句。
SELECT t.terminal_id FROM terminal t where t. terminal_id LIKE ' %'/span> and t. program_registrations like '%"program": "MY_PROGRAM_NAME"%';
這在這個用例中是可行的,但在語意上是錯誤的,因此,它不應該作業是正確的。試圖使用結構化的查詢語言來選擇非結構化的資料是沒有意義的
唯一的解決方案是使用結構化的查詢語言。
唯一的解決方案是將資料視為DB搜索條件的字符,并在查詢完成后將其視為物件串列,然后在Java中執行行的過濾。雖然這使得分頁功能變得相當無用。
一個可能的解決方案是擁有一個用于 DB 搜索條件的二級只讀字串版本的列,該列不會被 AttributeConverter 轉換為 JSON。
@JsonIgnore
@Column(name = "programRegistrations" , insertable = false, updatable = false)
private String programRegistrationsStr;
真正的解決方案是當你想對該資料進行結構化查詢時,不要使用非結構化的資料因此,將資料轉換為支持JSON原生查詢的資料庫,或者在DDL中正確建模資料。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/317511.html
標籤:
