POSJSONHELPER庫是一個開源項目,為PostgreSQL JSON功能提供了Hibernate查詢的支持。庫還支持PostgreSQL文本搜索功能。要了解如何使用文本搜索組件的更多信息,請檢查文本模塊的說明。該庫是用Java編程語言編寫的。這一刻的項目支持Hibernate版本5和6。 Java的必需版本至少是Hibernate 5 Support和Hibernate 6版本的第8版。
該項目可在中央Maven存儲庫中找到。您可以通過將其添加為項目描述符文件(pom.xml)中的依賴項來使用它。
對於冬眠5:
< dependency >
< groupId >com.github.starnowski.posjsonhelper</ groupId >
< artifactId >hibernate5</ artifactId >
< version >0.4.2</ version >
</ dependency >對於冬眠6:
< dependency >
< groupId >com.github.starnowski.posjsonhelper</ groupId >
< artifactId >hibernate6</ artifactId >
< version >0.4.2</ version >
</ dependency >POSJSONHELPER庫沒有瞬態依賴性對Hibernate庫。因此,請記住,必須在您的項目中分別添加Hibernate依賴性,如下所示:
< dependency >
< groupId >org.hibernate</ groupId >
< artifactId >hibernate-core</ artifactId >
< version >????</ version >
</ dependency >請檢查Hibernate兼容性版本矩陣以檢查正確的版本。
與JSON操作相關的某些功能的默認實現要求org.json:JSON庫。但是,有一些方法可以實現特定的接口,而在庫下方可能不需要添加。
< dependency >
< groupId >org.json</ groupId >
< artifactId >json</ artifactId >
< version >20240303</ version >
</ dependency >如果有人想從源頭本地構建該項目,請參閱contruting.md文件,以檢查如何在本地設置該項目。
重要的!本節僅適用於Hibernate 5。要能夠使用項目中的PosJsonHelper庫,則必須指定正確的Hibernate方言。圖書館實現了很少有擴展的包裝器,該包裝器已經存在於PostgreSQL的Hibernate方言:
方言必須在Hibernate配置文件中設置:例如:
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< hibernate-configuration xmlns = " http://www.hibernate.org/xsd/orm/cfg " >
< session-factory >
< property name = " hibernate.dialect " >com.github.starnowski.posjsonhelper.hibernate5.dialects.PostgreSQL95DialectWrapper</ property >
...或例如在春季框架配置屬性文件中:
...
spring.jpa.properties.hibernate.dialect =com.github.starnowski.posjsonhelper.hibernate5.dialects.PostgreSQL95DialectWrapper
...如果您已經具有擴展冬眠方言類型的類型,並且您的項目需要。您可以為您的類型添加調整,以便它使用Postgresqledialectenricher組件。
import com . github . starnowski . posjsonhelper . hibernate5 . PostgreSQLDialectEnricher ;
import org . hibernate . dialect . PostgreSQL95Dialect ;
public class PostgreSQLDialectWithDifferentSchema extends PostgreSQL95Dialect {
public PostgreSQLDialectWithDifferentSchema () {
PostgreSQLDialectEnricher enricher = new PostgreSQLDialectEnricher ();
enricher . enrich ( this );
}
}重要的!本節僅適用於Hibernate 6。要使用使用Hibernate 6的項目中的posjsonhelper庫,必須有一個指定的org.hibernate.boot.model.model.functioncontributor實現。庫具有該界面的實現,即com.github.starnowski.posjsonhelper.hibernate6.posjsonhelperfunctioncontributor。
要使用此實現,需要使用名稱“ org.hibernate.boot.model.functionContributor”創建文件。
替代解決方案是使用com.github.starnowski.posjsonhelper.hibernate6.sqmfunctionregistrymistrymenricher組件在應用程序啟動期間。就像在下面的示例中使用彈簧框架的使用一樣。
import com . github . starnowski . posjsonhelper . hibernate6 . SqmFunctionRegistryEnricher ;
import jakarta . persistence . EntityManager ;
import org . hibernate . query . sqm . NodeBuilder ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . context . ApplicationListener ;
import org . springframework . context . annotation . Configuration ;
import org . springframework . context . event . ContextRefreshedEvent ;
@ Configuration
public class FunctionDescriptorConfiguration implements
ApplicationListener < ContextRefreshedEvent > {
@ Autowired
private EntityManager entityManager ;
@ Override
public void onApplicationEvent ( ContextRefreshedEvent event ) {
NodeBuilder nodeBuilder = ( NodeBuilder ) entityManager . getCriteriaBuilder ();
SqmFunctionRegistryEnricher sqmFunctionRegistryEnricher = new SqmFunctionRegistryEnricher ();
sqmFunctionRegistryEnricher . enrich ( nodeBuilder . getQueryEngine (). getSqmFunctionRegistry ());
}
}要使用POSJSONHELPER庫,需要創建一些執行JSON運算符的SQL函數。一些JSON操作員不能被冬眠執行,因為必須逃脫它們。對於默認配置,庫需要以下功能創建以下功能。
CREATE OR REPLACE FUNCTION jsonb_all_array_strings_exist (jsonb, text []) RETURNS boolean AS $$
SELECT $ 1 ?& $ 2 ;
$$ LANGUAGE SQL;
CREATE OR REPLACE FUNCTION jsonb_any_array_strings_exist (jsonb, text []) RETURNS boolean AS $$
SELECT $ 1 ?| $ 2 ;
$$ LANGUAGE SQL;可以在集成測試期間執行生成的DDL語句,也可以由對數據庫(例如Liquibase或Flyway)應用更改的工具使用。重要的!如果需要使用相似的功能,但具有不同的名稱,則必須在應用程序屬性中指定。之所以需要,是因為類型擴展了冬眠方言類型,即“如何附加postgresql方言”](#操作對象 - 觸及 - 觸及postgresql方言)部分可能無法訪問應用程序上下文(IOC)。但是,如果應以不同的方式傳遞此類屬性,則PostgreSqledialectenricher類型也具有傳遞上下文對象的方法(請檢查核心上下文和Hibernate上下文)
上下文類保存圖書館使用的功能的名稱。方言類使用CoreContextPropertiessupplier組件,該組件基於系統屬性生成上下文對象。
也可以使用DatabaseOperationExecutorFacade類型來編程添加DDL。下面有有關如何使用彈簧框架上下文應用DDL更改的示例。
import com . github . starnowski . posjsonhelper . core . Context ;
import com . github . starnowski . posjsonhelper . core . DatabaseOperationExecutorFacade ;
import com . github . starnowski . posjsonhelper . core . DatabaseOperationType ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . context . ApplicationListener ;
import org . springframework . context . annotation . Configuration ;
import org . springframework . context . event . ContextRefreshedEvent ;
import javax . sql . DataSource ;
@ Configuration
public class SQLFunctionsConfiguration implements
ApplicationListener < ContextRefreshedEvent > {
@ Autowired
private Context context ;
@ Autowired
private DataSource dataSource ;
@ Override
public void onApplicationEvent ( ContextRefreshedEvent contextRefreshedEvent ) {
DatabaseOperationExecutorFacade facade = new DatabaseOperationExecutorFacade ();
try {
facade . execute ( dataSource , context , DatabaseOperationType . LOG_ALL );
facade . execute ( dataSource , context , DatabaseOperationType . CREATE );
facade . execute ( dataSource , context , DatabaseOperationType . VALIDATE );
} catch ( Exception e ) {
throw new RuntimeException ( "Error during initialization of sql functions for jsonb type operations" , e );
}
}
}有一些操作可以由數據庫executorfacade對象執行
| 屬性名稱 | 描述 |
|---|---|
| 創造 | 將DDL更改應用於數據庫 |
| 證實 | 驗證是否將DDL更改應用於數據庫 |
| 降低 | 丟棄數據庫中的DDL更改 |
| log_all | 顯示用於創建,驗證和刪除操作的DDL腳本 |
為了簡化說明,讓我們假設我們有一個數據庫表,其中一列存儲JSONB類型。
create table item (
id int8 not null ,
jsonb_content jsonb,
primary key (id)
)對於此表,我們可以使用任何JSON插入行,如以下示例:
INSERT INTO item (id, jsonb_content) VALUES ( 1 , ' {"top_element_with_set_of_values":["TAG1","TAG2","TAG11","TAG12","TAG21","TAG22"]} ' );
INSERT INTO item (id, jsonb_content) VALUES ( 2 , ' {"top_element_with_set_of_values":["TAG3"]} ' );
-- item without any properties, just an empty json
INSERT INTO item (id, jsonb_content) VALUES ( 6 , ' {} ' );
-- int values
INSERT INTO item (id, jsonb_content) VALUES ( 7 , ' {"integer_value": 132} ' );
-- double values
INSERT INTO item (id, jsonb_content) VALUES ( 10 , ' {"double_value": 353.01} ' );
INSERT INTO item (id, jsonb_content) VALUES ( 11 , ' {"double_value": -1137.98} ' );
-- enum values
INSERT INTO item (id, jsonb_content) VALUES ( 13 , ' {"enum_value": "SUPER"} ' );
-- string values
INSERT INTO item (id, jsonb_content) VALUES ( 18 , ' {"string_value": "the end of records"} ' );大多數謂詞組件都使用Hibernate上下文對象。它主要保存項目中使用的Hibernate功能名稱的名稱。方言類和函數contributor類型使用Hibernatecontextpropertiessupplier組件,該組件基於系統屬性生成HibernateContext對象。如果不需要更改PSOJSONHELPER運算符的默認HQL函數名稱,則甚至使用Builder組件創建的HibernateContext,如下:
HibernateContext hibernateContext = HibernateContext . builder (). build ();“ JSONB_EXTRACT_PATH”是PostgreSQL函數,它返回JSONB值指向路徑元素以“ text []”(等效於#> operator)指向的路徑元素。這很有用,因為許多功能都使用“ JSONB”類型進行執行。請查看PostgreSQL文檔以獲取更多信息。 Hibernate 5示例:下面有一個方法的示例,該方法返回一個項目對象的列表,JSON Content屬性“ TOP_ELEMENT_WITH_SET_SET_OF_VALUES”包含一個精確的值集。該示例使用JSONBALLARRARSTRINGSEXISTPREDICATE。
@ Autowired
private HibernateContext hibernateContext ;
@ Autowired
private EntityManager entityManager ;
public List < Item > findAllByAllMatchingTags ( Set < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( new JsonbAllArrayStringsExistPredicate ( hibernateContext , ( CriteriaBuilderImpl ) cb , new JsonBExtractPath (( CriteriaBuilderImpl ) cb , singletonList ( "top_element_with_set_of_values" ), root . get ( "jsonbContent" )), tags . toArray ( new String [ 0 ])));
return entityManager . createQuery ( query ). getResultList ();
}對於上述方法,Hibernate將執行HQL查詢:
select
generatedAlias0
from
Item as generatedAlias0
where
jsonb_all_array_strings_exist( jsonb_extract_path( generatedAlias0 . jsonbContent , :param0 ) , json_function_json_array(:param1)) = TRUE本機SQL將具有以下形式:
select
item0_ . id as id1_0_,
item0_ . jsonb_content as jsonb_co2_0_
from
item item0_
where
jsonb_all_array_strings_exist(jsonb_extract_path( item0_ . jsonb_content ,?), array[?]) = true有關更多詳細信息,請檢查測試中使用的DAO。
Hibernate 6示例:
下面有與上面相同的示例,但對於休眠6。
import org . hibernate . query . sqm . NodeBuilder ;
....
@ Autowired
private HibernateContext hibernateContext ;
@ Autowired
private EntityManager entityManager ;
public List < Item > findAllByAllMatchingTags ( Set < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( new JsonbAllArrayStringsExistPredicate ( hibernateContext , ( NodeBuilder ) cb , new JsonBExtractPath ( root . get ( "jsonbContent" ), ( NodeBuilder ) cb , singletonList ( "top_element_with_set_of_values" )), tags . toArray ( new String [ 0 ])));
return entityManager . createQuery ( query ). getResultList ();
}有關更多詳細信息,請檢查測試中使用的DAO。
“ jsonb_extract_path_text”是postgresql函數,返回JSON值,如文本所指向的路徑元素所指向的路徑元素所傳遞的“ text []”(等效於#>>> >>操作員)。請查看PostgreSQL文檔以獲取更多信息。下面有一個方法的Hibernate 5示例,該方法查找包含與“類似”運算符匹配的特定字符串值的項目。
public List < Item > findAllByStringValueAndLikeOperator ( String expression ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( cb . like ( new JsonBExtractPathText (( CriteriaBuilderImpl ) cb , singletonList ( "string_value" ), root . get ( "jsonbContent" )), expression ));
return entityManager . createQuery ( query ). getResultList ();
}對於上述方法,Hibernate將執行HQL查詢:
select
generatedAlias0
from
Item as generatedAlias0
where
jsonb_extract_path_text( generatedAlias0 . jsonbContent , :param0 ) like :param1本機SQL將具有以下形式:
select
item0_ . id as id1_0_,
item0_ . jsonb_content as jsonb_co2_0_
from
item item0_
where
jsonb_extract_path_text( item0_ . jsonb_content ,?) like ?有關In Operator的更多詳細信息和示例,或者如何使用數字值,請檢查測試中使用的DAO。
Hibernate 6示例:
下面有與上面相同的示例,但對於休眠6。
....
public List < Item > findAllByStringValueAndLikeOperator ( String expression ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( cb . like ( new JsonBExtractPathText ( root . get ( "jsonbContent" ), singletonList ( "string_value" ), ( NodeBuilder ) cb ), expression ));
return entityManager . createQuery ( query ). getResultList ();
}有關更多詳細信息,請檢查測試中使用的DAO。
JSONBALLARRARSTRINGSISTPREDICATE類型表示謂詞,該謂詞檢查是否在JSON Array屬性中存在傳遞的字符串數組。此謂詞的第一個示例是在“ JSONBExtractPath -jsonb_extract_path”部分中引入的。這些謂詞假定存在具有默認名稱JSONB_ALL_ARRAY_STRINGS_EXIST的SQL函數,在“ Apply DDL更改”部分中提到。以下示例與操作員的組合不提出並非所有搜索字符串的項目。示例僅適用於Hibernate 5!
public List < Item > findAllThatDoNotMatchByAllMatchingTags ( Set < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
Predicate notAllMatchingTags = cb . not ( new JsonbAllArrayStringsExistPredicate ( hibernateContext , ( CriteriaBuilderImpl ) cb , new JsonBExtractPath (( CriteriaBuilderImpl ) cb , singletonList ( "top_element_with_set_of_values" ), root . get ( "jsonbContent" )), tags . toArray ( new String [ 0 ])));
Predicate withoutSetOfValuesProperty = cb . isNull ( new JsonBExtractPath (( CriteriaBuilderImpl ) cb , singletonList ( "top_element_with_set_of_values" ), root . get ( "jsonbContent" )));
query . where ( cb . or ( withoutSetOfValuesProperty , notAllMatchingTags ));
return entityManager . createQuery ( query ). getResultList ();
}對於上述方法,Hibernate將執行HQL查詢:
select
generatedAlias0
from
Item as generatedAlias0
where
(
jsonb_extract_path( generatedAlias0 . jsonbContent , :param0 ) is null
)
or (
jsonb_all_array_strings_exist( jsonb_extract_path( generatedAlias0 . jsonbContent , :param1 ) , json_function_json_array(:param2, :param3)) = FALSE
)本機SQL將具有以下形式:
select
item0_ . id as id1_0_,
item0_ . jsonb_content as jsonb_co2_0_
from
item item0_
where
jsonb_extract_path( item0_ . jsonb_content ,?) is null
or jsonb_all_array_strings_exist(jsonb_extract_path( item0_ . jsonb_content ,?), array[?,?]) = falseHibernate 6示例:
下面有與上面相同的示例,但對於休眠6。
public List < Item > findAllThatDoNotMatchByAllMatchingTags ( Set < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
Predicate notAllMatchingTags = cb . not ( new JsonbAllArrayStringsExistPredicate ( hibernateContext , ( NodeBuilder ) cb , new JsonBExtractPath ( root . get ( "jsonbContent" ), ( NodeBuilder ) cb , singletonList ( "top_element_with_set_of_values" )), tags . toArray ( new String [ 0 ])));
Predicate withoutSetOfValuesProperty = cb . isNull ( new JsonBExtractPath ( root . get ( "jsonbContent" ), ( NodeBuilder ) cb , singletonList ( "top_element_with_set_of_values" )));
query . where ( cb . or ( withoutSetOfValuesProperty , notAllMatchingTags ));
return entityManager . createQuery ( query ). getResultList ();
}有關更多詳細信息,請檢查測試中使用的DAO。
JSONBANYARRAYSTRINGSTRINGSISTPREDICATE類型表示一個謂詞,該謂詞檢查是否在JSON Array屬性中存在傳遞的字符串數組。這些謂詞假定存在具有默認名稱JSONB_ARY_ARRAY_STRINGS_EXIST的SQL函數,在“ Apply DDL更改”部分中提到。下面有一個方法的示例,該方法查找所有屬性數組的項目包含至少一個從傳遞的數組作為方法參數傳遞的字符串。示例僅適用於Hibernate 5!
public List < Item > findAllByAnyMatchingTags ( HashSet < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( new JsonbAnyArrayStringsExistPredicate ( hibernateContext , ( CriteriaBuilderImpl ) cb , new JsonBExtractPath (( CriteriaBuilderImpl ) cb , singletonList ( "top_element_with_set_of_values" ), root . get ( "jsonbContent" )), tags . toArray ( new String [ 0 ])));
return entityManager . createQuery ( query ). getResultList ();
}對於上述方法,Hibernate將執行HQL查詢:
select
generatedAlias0
from
Item as generatedAlias0
where
jsonb_any_array_strings_exist( jsonb_extract_path( generatedAlias0 . jsonbContent , :param0 ) , json_function_json_array(:param1, :param2)) = TRUE本機SQL將具有以下形式:
select
item0_ . id as id1_0_,
item0_ . jsonb_content as jsonb_co2_0_
from
item item0_
where
jsonb_any_array_strings_exist(jsonb_extract_path( item0_ . jsonb_content ,?), array[?,?]) = trueHibernate 6示例:
下面有與上面相同的示例,但對於休眠6。
public List < Item > findAllByAnyMatchingTags ( HashSet < String > tags ) {
CriteriaBuilder cb = entityManager . getCriteriaBuilder ();
CriteriaQuery < Item > query = cb . createQuery ( Item . class );
Root < Item > root = query . from ( Item . class );
query . select ( root );
query . where ( new JsonbAnyArrayStringsExistPredicate ( hibernateContext , ( NodeBuilder ) cb , new JsonBExtractPath ( root . get ( "jsonbContent" ), ( NodeBuilder ) cb , singletonList ( "top_element_with_set_of_values" )), tags . toArray ( new String [ 0 ])));
return entityManager . createQuery ( query ). getResultList ();
}有關In Operator的更多詳細信息和示例,或者如何使用數字值,請檢查測試中使用的DAO。
該庫也可以用於JSON修改操作。默認情況下,在Hibernate中,我們可以通過設置其整個值來更新帶有JSON內容的列。 POSJSONHELPER庫還允許您通過設置,替換或刪除單個JSON屬性來修改JSON內容,而無需更換其完整內容。該庫包含幾個允許此類操作的JSON功能和操作員。
JSONB_SET功能的包裝器。該函數基於JSON路徑設置或替換JSON屬性的值。查看以下示例,有關如何與Criteriaupdate組件一起使用:
// GIVEN
Long itemId = 19L ;
String property = "birthday" ;
String value = "1970-01-01" ;
String expectedJson = "{ " child " : { " pets " : [ " dog " ], " birthday " : " 1970-01-01 " }}" ;
// when
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
// Set the property you want to update and the new value
criteriaUpdate . set ( "jsonbContent" , new JsonbSetFunction (( NodeBuilder ) entityManager . getCriteriaBuilder (), root . get ( "jsonbContent" ), new JsonTextArrayBuilder (). append ( "child" ). append ( property ). build (). toString (), JSONObject . quote ( value ), hibernateContext ));
// Add any conditions to restrict which entities will be updated
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), itemId ));
// Execute the update
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// then
Item item = tested . findById ( itemId );
assertThat (( String ) JsonPath . read ( item . getJsonbContent (), "$.child." + property )). isEqualTo ( value );
JSONObject jsonObject = new JSONObject ( expectedJson );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( jsonObject . toString ());這將生成以下SQL Update語句:
update
item
set
jsonb_content = jsonb_set(jsonb_content, ?:: text [], ?::jsonb)
where
id = ?
Hibernate:
select
i1_0 . id ,
i1_0 . jsonb_content
from
item i1_0
where
i1_0 . id = ?該函數也可以在HQL語句中使用,如以下示例:
@ Transactional
public void updateJsonBySettingPropertyForItemByHQL ( Long itemId , String property , String value ) {
// Execute the update
String hqlUpdate = "UPDATE Item SET jsonbContent = jsonb_set(jsonbContent, %s(:path, 'text[]'), %s(:json, 'jsonb' ) ) WHERE id = :id" . formatted ( hibernateContext . getCastFunctionOperator (), hibernateContext . getCastFunctionOperator ());
int updatedEntities = entityManager . createQuery ( hqlUpdate )
. setParameter ( "id" , itemId )
. setParameter ( "path" , new JsonTextArrayBuilder (). append ( "child" ). append ( property ). build (). toString ())
. setParameter ( "json" , JSONObject . quote ( value ))
. executeUpdate ();
}串聯操作員的包裝器。包裝器將兩個JSONB值串聯成一個新的JSONB值。查看以下示例,有關如何與Criteriaupdate組件一起使用:
// GIVEN
Long itemId = 19l ;
String property = "birthday" ;
String value = "1970-01-01" ;
// WHEN
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
JSONObject jsonObject = new JSONObject ();
jsonObject . put ( "child" , new JSONObject ());
jsonObject . getJSONObject ( "child" ). put ( property , value );
criteriaUpdate . set ( "jsonbContent" , new ConcatenateJsonbOperator (( NodeBuilder ) entityManager . getCriteriaBuilder (), root . get ( "jsonbContent" ), jsonObject . toString (), hibernateContext ));
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), itemId ));
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// THEN
Item item = tested . findById ( itemId );
assertThat (( String ) JsonPath . read ( item . getJsonbContent (), "$.child." + property )). isEqualTo ( value );
JSONObject expectedJsonObject = new JSONObject (). put ( property , value );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$.child" ));
assertThat ( document . jsonString ()). isEqualTo ( expectedJsonObject . toString ());這將生成以下SQL Update語句:
update
item
set
jsonb_content = jsonb_content || ?::jsonb
where
id = ?
Hibernate:
select
i1_0 . id ,
i1_0 . jsonb_content
from
item i1_0
where
i1_0 . id = ?該函數也可以在HQL語句中使用,如以下示例:
@ Transactional
public void updateJsonPropertyForItemByHQL ( Long itemId , String property , String value ) throws JSONException {
JSONObject jsonObject = new JSONObject ();
jsonObject . put ( "child" , new JSONObject ());
jsonObject . getJSONObject ( "child" ). put ( property , value );
String hqlUpdate = "UPDATE Item SET jsonbContent = %s(jsonbContent, %s(:json, 'jsonb' ) ) WHERE id = :id" . formatted ( hibernateContext . getConcatenateJsonbOperator (), hibernateContext . getCastFunctionOperator ());
int updatedEntities = entityManager . createQuery ( hqlUpdate )
. setParameter ( "id" , itemId )
. setParameter ( "json" , jsonObject . toString ())
. executeUpdate ();
}刪除操作員的包裝器'# - '。包裝器基於指定路徑的索引刪除字段或數組元素,其中路徑元素可以是字段鍵或數組索引。查看以下示例,有關如何與Criteriaupdate組件一起使用:
// GIVEN
Item item = tested . findById ( 19L );
JSONObject jsonObject = new JSONObject ( "{ " child " : { " pets " : [ " dog " ]}}" );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( jsonObject . toString ());
// WHEN
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
// Set the property you want to update and the new value
criteriaUpdate . set ( "jsonbContent" , new DeleteJsonbBySpecifiedPathOperator (( NodeBuilder ) entityManager . getCriteriaBuilder (), root . get ( "jsonbContent" ), new JsonTextArrayBuilder (). append ( "child" ). append ( "pets" ). build (). toString (), hibernateContext ));
// Add any conditions to restrict which entities will be updated
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), 19L ));
// Execute the update
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// THEN
entityManager . refresh ( item );
jsonObject = new JSONObject ( "{ " child " : {}}" );
document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( jsonObject . toString ());這將生成以下SQL Update語句:
update
item
set
jsonb_content = (jsonb_content # - ?::text[])
where
id = ?該函數也可以在HQL語句中使用,如以下示例:
@ Transactional
public void updateJsonByDeletingSpecificPropertyForItemByHql ( Long itemId , String property ) {
// Execute the update
String hqlUpdate = "UPDATE Item SET jsonbContent = %s(jsonbContent, %s(:path, 'text[]') ) WHERE id = :id" . formatted ( hibernateContext . getDeleteJsonBySpecificPathOperator (), hibernateContext . getCastFunctionOperator ());
int updatedEntities = entityManager . createQuery ( hqlUpdate )
. setParameter ( "id" , itemId )
. setParameter ( "path" , new JsonTextArrayBuilder (). append ( "child" ). append ( property ). build (). toString ())
. executeUpdate ();
}RemovejsonValuesFromjSonArrayFunction類型是一個冬眠操作員,可調用PosjsonHelper庫生成的SQL函數。默認情況下,生成的函數看起來像以下示例:
CREATE OR REPLACE FUNCTION {{schema}}.remove_values_from_json_array(input_json jsonb, values_to_remove jsonb) RETURNS jsonb AS $$
DECLARE
result jsonb;
BEGIN
IF jsonb_typeof(values_to_remove) <> ' array ' THEN
RAISE EXCEPTION ' values_to_remove must be a JSON array ' ;
END IF;
result : = (
SELECT jsonb_agg(element)
FROM jsonb_array_elements(input_json) AS element
WHERE NOT (element IN ( SELECT jsonb_array_elements(values_to_remove)))
);
RETURN COALESCE(result, ' [] ' ::jsonb);
END;
$$ LANGUAGE plpgsql;該函數具有兩個輸入參數。首先是JSON數組,它是該功能將返回的結果的基本數組。第二個參數也是一個JSON數組,它表示應從結果數組中刪除的元素。以下是如何與其他操作員一起使用SQL Update語句更新JSON列的代碼示例。
// GIVEN
Item item = tested . findById ( 24L );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " crab " , " chameleon " ]}, " inventory " :[ " mask " , " fins " , " compass " ]}" );
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
NodeBuilder nodeBuilder = ( NodeBuilder ) entityManager . getCriteriaBuilder ();
JSONArray toRemoveJSONArray = new JSONArray ( Arrays . asList ( "mask" , "compass" ));
RemoveJsonValuesFromJsonArrayFunction deleteOperator = new RemoveJsonValuesFromJsonArrayFunction ( nodeBuilder , new JsonBExtractPath ( root . get ( "jsonbContent" ), nodeBuilder , Arrays . asList ( "inventory" )), toRemoveJSONArray . toString (), hibernateContext );
JsonbSetFunction jsonbSetFunction = new JsonbSetFunction ( nodeBuilder , ( SqmTypedNode ) root . get ( "jsonbContent" ), new JsonTextArrayBuilder (). append ( "inventory" ). build (). toString (), deleteOperator , hibernateContext );
// Set the property you want to update and the new value
criteriaUpdate . set ( "jsonbContent" , jsonbSetFunction );
// Add any conditions to restrict which entities will be updated
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), 24L ));
// WHEN
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// THEN
entityManager . refresh ( item );
document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " crab " , " chameleon " ]}, " inventory " :[ " fins " ]}" );同一示例,但與HQL查詢示例:
// GIVEN
Item item = tested . findById ( 24L );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " crab " , " chameleon " ]}, " inventory " :[ " mask " , " fins " , " compass " ]}" );
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
JSONArray toRemoveJSONArray = new JSONArray ( Arrays . asList ( "mask" , "compass" ));
String hqlUpdate = "UPDATE Item SET jsonbContent = %s(jsonbContent, %s(:path, 'text[]'), %s(jsonb_extract_path( jsonbContent , 'inventory' ), %s(:to_remove, 'jsonb')) ) WHERE id = :id" . formatted ( JSONB_SET_FUNCTION_NAME , hibernateContext . getCastFunctionOperator (), hibernateContext . getRemoveJsonValuesFromJsonArrayFunction (), hibernateContext . getCastFunctionOperator ());
// WHEN
entityManager . createQuery ( hqlUpdate )
. setParameter ( "id" , 24L )
. setParameter ( "path" , new JsonTextArrayBuilder (). append ( "inventory" ). build (). toString ())
. setParameter ( "to_remove" , toRemoveJSONArray . toString ())
. executeUpdate ();
// THEN
entityManager . refresh ( item );
document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " crab " , " chameleon " ]}, " inventory " :[ " fins " ]}" );這兩個示例將在SQL語句以下生成:
update
item
set
jsonb_content = jsonb_set(jsonb_content, ?:: text [], remove_values_from_json_array(jsonb_extract_path(jsonb_content, ?), ?::jsonb))
where
id = ?使用單個JSONB_SET函數使用單個Update語句為JSON設置單個屬性可能很有用,但是,能夠使用單個更新語句設置在JSON樹的不同級別上設置多個屬性可能更有用。
避免在下面的檢查代碼示例:
// GIVEN
Item item = tested . findById ( 23L );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " dog " ]}, " inventory " :[ " mask " , " fins " ], " nicknames " :{ " school " : " bambo " , " childhood " : " bob " }}" );
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
Hibernate6JsonUpdateStatementBuilder hibernate6JsonUpdateStatementBuilder = new Hibernate6JsonUpdateStatementBuilder ( root . get ( "jsonbContent" ), ( NodeBuilder ) entityManager . getCriteriaBuilder (), hibernateContext );
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "child" ). append ( "birthday" ). build (), quote ( "2021-11-23" ));
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "child" ). append ( "pets" ). build (), "[ " cat " ]" );
hibernate6JsonUpdateStatementBuilder . appendDeleteBySpecificPath ( new JsonTextArrayBuilder (). append ( "inventory" ). append ( "0" ). build ());
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "parents" ). append ( 0 ). build (), "{ " type " : " mom " , " name " : " simone " }" );
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "parents" ). build (), "[]" );
hibernate6JsonUpdateStatementBuilder . appendDeleteBySpecificPath ( new JsonTextArrayBuilder (). append ( "nicknames" ). append ( "childhood" ). build ());
// Set the property you want to update and the new value
criteriaUpdate . set ( "jsonbContent" , hibernate6JsonUpdateStatementBuilder . build ());
// Add any conditions to restrict which entities will be updated
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), 23L ));
// WHEN
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// THEN
entityManager . refresh ( item );
document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " cat " ], " birthday " : " 2021-11-23 " }, " parents " :[{ " name " : " simone " , " type " : " mom " }], " inventory " :[ " fins " ], " nicknames " :{ " school " : " bambo " }}" );在上面的代碼中,我們希望設置三個JSON屬性“ child.birthday”,“ child.pets”和“ parters”,並刪除另外兩個“庫存”,“ 0.0”和“ nicknames.childhood”。 “父母”財產是假定是陣列的新財產。儘管設置具有某些值的新數組屬性可以通過單個操作來完成,但是出於演示目的,我們使用了兩個操作。一種是為了設置名為“父母”的新屬性,將空的JSON數組作為值。以及將數組元素設置為特定索引的另一個操作。如果不存在較高的屬性,則必須在內部屬性之前創建它。幸運的是,Hibernate6jsonupDateTeTatementBuilder類型的默認實例具有適當的排序和過濾組件,可幫助您設置正確的操作順序。因此,在添加創建陣列操作之前還是之後,我們是否添加附加儀表操作都沒關係。默認情況下,將在添加或替換內容的內容之前添加刪除內容的操作。當然,可以通過將這些組件設置為null來禁用此行為。有關更多詳細信息,請檢查Javadoc中的Hibernate6jsonupDateTestatementBuilder類型。
此代碼在SQL語句下面生成:
update
item
set
jsonb_content =
jsonb_set(
jsonb_set(
jsonb_set(
jsonb_set(
(
(jsonb_content # - ?::text[]) -- the most nested #- operator
# - ?::text[])
, ?:: text [], ?::jsonb) -- the most nested jsonb_set operation
, ?:: text [], ?::jsonb)
, ?:: text [], ?::jsonb)
, ?:: text [], ?::jsonb)
where
id = ?此準備的語句的最內部JSONB_SET函數執行將為“父母”屬性設置一個空數組。
構建器具有設置值的方法:
刪除屬性:
appenddeletebyspecificpath(jsontextarray jsontextarray)
添加數組元素
刪除數組元素
默認情況下,與JSON數組上的修改有關的一些方法需要org.json.json庫(檢查可選依賴項)。 However, it is possible to pass custom implementation of interface that maps collection object to json array value with "withCollectionToJsonArrayStringMapper(com.github.starnowski.posjsonhelper.hibernate6.Hibernate6JsonUpdateStatementBuilder.CollectionToJsonArrayStringMapper)" builder method
Hibernate6jsonupDateTestatementBuilder類型是通用的。第二個通用類型是一種自定義值,可以添加到Hibernate6jsonupDateTeTatementBuilder上下文中。以下是一個代碼示例,其類型代表數組操作(應添加到數組中並刪除的元素)。
自定義值類型:
private static class JsonArrayOperations {
private final List < String > toDelete ;
private final List < String > toAdd ;
public JsonArrayOperations ( List < String > toDelete , List < String > toAdd ) {
this . toDelete = toDelete ;
this . toAdd = toAdd ;
}
public List < String > getToDelete () {
return toDelete ;
}
public List < String > getToAdd () {
return toAdd ;
}
}用法示例:
// GIVEN
Item item = tested . findById ( 24L );
DocumentContext document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " child " :{ " pets " :[ " crab " , " chameleon " ]}, " inventory " :[ " mask " , " fins " , " compass " ]}" );
CriteriaUpdate < Item > criteriaUpdate = entityManager . getCriteriaBuilder (). createCriteriaUpdate ( Item . class );
Root < Item > root = criteriaUpdate . from ( Item . class );
Hibernate6JsonUpdateStatementBuilder < Object , JsonArrayOperations > hibernate6JsonUpdateStatementBuilder = new Hibernate6JsonUpdateStatementBuilder ( root . get ( "jsonbContent" ), ( NodeBuilder ) entityManager . getCriteriaBuilder (), hibernateContext );
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "child" ). append ( "pets" ). build (), null , new JsonArrayOperations ( Arrays . asList ( "crab" , "ant" ), Arrays . asList ( "lion" , "dolphin" )));
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "name" ). build (), JSONObject . quote ( "Simon" ));
hibernate6JsonUpdateStatementBuilder . appendJsonbSet ( new JsonTextArrayBuilder (). append ( "inventory" ). build (), null , new JsonArrayOperations ( Arrays . asList ( "compass" , "mask" ), Arrays . asList ( "knife" )));
hibernate6JsonUpdateStatementBuilder . withJsonbSetFunctionFactory ( new Hibernate6JsonUpdateStatementBuilder . DefaultJsonbSetFunctionFactory < Object , JsonArrayOperations >() {
public JsonbSetFunction build ( NodeBuilder nodeBuilder , Path < Object > rootPath , JsonUpdateStatementConfiguration . JsonUpdateStatementOperation < JsonArrayOperations > operation , HibernateContext hibernateContext ) {
if ( operation . getCustomValue () != null ) {
JSONArray toAddJSONArray = new JSONArray ( operation . getCustomValue (). getToAdd ());
ConcatenateJsonbOperator concatenateOperator = new ConcatenateJsonbOperator ( nodeBuilder , new JsonBExtractPath ( rootPath , nodeBuilder , operation . getJsonTextArray (). getPath (). stream (). map ( ob -> ob . toString ()). collect ( Collectors . toList ())), toAddJSONArray . toString (), hibernateContext );
JSONArray toRemoveJSONArray = new JSONArray ( operation . getCustomValue (). getToDelete ());
RemoveJsonValuesFromJsonArrayFunction deleteOperator = new RemoveJsonValuesFromJsonArrayFunction ( nodeBuilder , concatenateOperator , toRemoveJSONArray . toString (), hibernateContext );
return new JsonbSetFunction ( nodeBuilder , ( SqmTypedNode ) rootPath , operation . getJsonTextArray (). toString (), deleteOperator , hibernateContext );
} else {
return super . build ( nodeBuilder , rootPath , operation , hibernateContext );
}
}
@ Override
public JsonbSetFunction build ( NodeBuilder nodeBuilder , SqmTypedNode sqmTypedNode , JsonUpdateStatementConfiguration . JsonUpdateStatementOperation < JsonArrayOperations > operation , HibernateContext hibernateContext ) {
if ( operation . getCustomValue () != null ) {
JSONArray toAddJSONArray = new JSONArray ( operation . getCustomValue (). getToAdd ());
ConcatenateJsonbOperator concatenateOperator = new ConcatenateJsonbOperator ( nodeBuilder , new JsonBExtractPath ( root . get ( "jsonbContent" ), nodeBuilder , operation . getJsonTextArray (). getPath (). stream (). map ( ob -> ob . toString ()). collect ( Collectors . toList ())), toAddJSONArray . toString (), hibernateContext );
JSONArray toRemoveJSONArray = new JSONArray ( operation . getCustomValue (). getToDelete ());
RemoveJsonValuesFromJsonArrayFunction deleteOperator = new RemoveJsonValuesFromJsonArrayFunction ( nodeBuilder , concatenateOperator , toRemoveJSONArray . toString (), hibernateContext );
return new JsonbSetFunction ( nodeBuilder , sqmTypedNode , operation . getJsonTextArray (). toString (), deleteOperator , hibernateContext );
} else {
return super . build ( nodeBuilder , sqmTypedNode , operation , hibernateContext );
}
}
});
// Set the property you want to update and the new value
criteriaUpdate . set ( "jsonbContent" , hibernate6JsonUpdateStatementBuilder . build ());
// Add any conditions to restrict which entities will be updated
criteriaUpdate . where ( entityManager . getCriteriaBuilder (). equal ( root . get ( "id" ), 24L ));
// WHEN
entityManager . createQuery ( criteriaUpdate ). executeUpdate ();
// THEN
entityManager . refresh ( item );
document = JsonPath . parse (( Object ) JsonPath . read ( item . getJsonbContent (), "$" ));
assertThat ( document . jsonString ()). isEqualTo ( "{ " name " : " Simon " , " child " :{ " pets " :[ " chameleon " , " lion " , " dolphin " ]}, " inventory " :[ " fins " , " knife " ]}" );| 屬性名稱 | 描述 |
|---|---|
| com.github.starnowski.posjsonhelper.core.functions.jsonb_all_array_array_strings_exist | SQL函數的名稱,該函數檢查是否全部傳遞的元素,因為文本[]存在於JSON數組屬性中。默認情況下,名稱為jsonb_all_array_strings_exist |
| com.github.starnowski.posjsonhelper.core.functions.jsonb_any_array_array_strings_exist | SQL函數的名稱,該函數檢查是否傳入的元素,因為文本[]存在於JSON數組屬性中。默認情況下,名稱為jsonb_any_array_strings_exist |
| com.github.starnowski.posjsonhelper.core.functions.remove_values_from_json_array | 通過刪除JSONB數組中的元素作為函數輸入,返回JSONB數組的SQL函數的名稱。默認情況下,名稱為remove_values_from_json_array |
| com.github.starnowski.posjsonhelper.core.schema | 應該創建SQL功能的數據庫架構的名稱 |
| com.github.starnowski.posjsonhelper.core.hibernate.functions.jsonb_all_arl_array_strings_exist | 調用由com.github.starnowski.posjsonhelper.core.core.functions.jsonb_all_arl_array_array_strings_exist屬性指定的SQL函數的HQL函數的名稱。默認情況下,名稱為jsonb_all_array_strings_exist |
| com.github.starnowski.posjsonhelper.core.hibernate.functions.jsonb_any_array_array_strings_exist | 調用由com.github.starnowski.posjsonhelper.core.core.functions.jsonb_any_ary_array_array_ertings_exist屬性指定的SQL函數的HQL函數的名稱。默認情況下,名稱為jsonb_any_array_strings_exist |
| com.github.starnowski.posjsonhelper.core.hibernate.functions.json_function_json_array | 將數組運算符在PostgreSQL中包裝的HQL函數的名稱。默認情況下,名稱為json_function_json_array |
| com.github.starnowski.posjsonhelper.core.hibernate.functions.remove_values_from_json_array | 通過刪除JSONB數組中的元素作為函數輸入,將返回JSONB數組返回JSONB數組的HQL函數的名稱。默認情況下,名稱為remove_values_from_json_array |
| com.github.starnowski.posjsonhelper.core.hibernate.functions.sqldefinitioncontextfactory.types | 存儲com.github.starnowski.posjsonhelper.core.core.sql.isqldefinitioncontextfactfactory類型的系統屬性。而不是加載可以在“ com.github.starnowski.posjsonhelper”的class路徑上找到的類型。列表上的類型由逗號字符分開。 ”。 |
| com.github.starnowski.posjsonhelper.hibernate6.functionDescriptorregisterfactory.types | (僅在Hibernate 6中使用)存儲com.github.starnowski.posjsonhelper.hibernate6.descriptor.functiondescriptDescriptDescriptDescriptDescriptOrregisterFactoriessupplier類型的系統屬性。而不是加載可以在“ com.github.starnowski.posjsonhelper”的class路徑上找到的類型。列表上的類型由逗號字符分開。 ”。 |
| com.github.starnowski.posjsonhelper.hibernate6.functionDescriptorregisterfactory.types.excluded | (僅在Hibernate 6中使用)存儲com.github.starnowski.posjsonhelper.hibernate6.descriptor.functiondescriptDescriptDescriptDescriptDescriptOrregisterFactoriessupplier類型的系統屬性。如果“ com.github.starnowski.posjsonhelper.hibernate6.functionDescriptDescriptOrregisterFactory.types”屬性也指定,然後“ com.github.starnowski.posjsonhelper.hibernate6.functionDescriptDescriptDescriptDescriptDescriptDescriptDescriptDescriptDescriptDescriptorregisterfactory.expespes.exclitity.exclitity”列表上的類型由逗號字符分開。 ”。 |
兼容性矩陣與休眠6。
| posjsonhelper | 休眠6 |
|---|---|
| 0.3.0 | 6.4.0.最終 |
| 0.2.0-0.2.1 | 6.1.5.最終 |
休眠軟件包,版本或類等方面的問題。
如果您面臨與缺少方法定義或類型相關的問題,例如:
java.lang.NoSuchMethodError: 'org.hibernate.query.criteria.JpaExpression
然後,請首先檢查您的項目是否在ClassPath上有Hibernate-Core庫。 Hibernate-Core是該項目的可選依賴性,您必須確保其已在項目中添加。請檢查類似的第145期。如果您在ClassPath上冬眠核心,並且問題仍然存在,請報告問題。