Spring boot Spring Data JPA postgres jsonb column INSERT/UPDATE - java

i'm struggling trying to update a record on a postgres table with a jsonb column.
What i'm trying to do with spring boot and JPA is running this statement that works great on postgres:
UPDATE data_report
SET error_details = error_details || '[{"error": "testError","record": {"start":"14:00","end":"20:00","id":"AAAA001","date":"2022-01-31"}}]'::jsonb
WHERE id = 91;
I've tried with Native Query:
#Transactional
#Modifying
#Query(value = "UPDATE data_integration_report SET error_details = error_details || :errors ::jsonb WHERE id = :id", nativeQuery = true)
void updateErrorDetail(#Param("id") Long id, #Param("errors") String errors);
but I'm getting error saying that syntax is not correct because ::jsonb is not recognized
I've tried with EntityManager
entityManager.createNativeQuery(
"UPDATE data_integration_report SET error_details = error_details || :errors ::jsonb WHERE id = :id"
).setParameter("id", 91L)
.setParameter("errors", data)
.executeUpdate();
Even here i'm getting error on syntax.
I've also tried to remove ::jsonb cast, but I'm receiving this error: "column is of type jsonb but expression is of type text"
I'm looking for some documentation or an example that can help me to find a solution.
Thanks in advance.

I think the immediate problem you are having is casting the incoming field incorrectly.
#Transactional
#Modifying
#Query(value = "UPDATE data_integration_report SET error_details = error_details || :errors ::jsonb WHERE id = :id", nativeQuery = true)
void updateErrorDetail(#Param("id") Long id, #Param("errors") String errors);
:errors ::jsonb has a space, so it sees the :: cast operation as a separate token. However, JPA will choke on :errors::jsonb (as I suspect you have discovered).
There are two ways to do a Postgres cast inside a query like this:
Escape the colons: :error\\:\\:jsonb
Use the cast function: cast(:error as jsonb)
However
There is an even better solution, and that is to use a hibernate type made for jsonb in your entity. The commonly accepted solution is this one: vladmihalcea /
hibernate-types

Related

Why is the first Query working and the second not? (Spring application JPA)

I have two Query's that I want to use in a Spring project (using JPA). The first one gets an account and this works correctly. For the second one I want it to be able to update the 'disabled' field in the database. The codes look like this:
// This is the first Query (works correctly)
#Query(value = "SELECT * FROM accounts WHERE email = ?1", nativeQuery = true)
Account findByEmailAddress(String emailAddress);
// This is the second Query (doesn't work)
#Modifying
#Query(value = "UPDATE accounts SET disabled = 1 WHERE email= ?1 ", nativeQuery = true)
int disableAccountByEmail(String emailAddress);
I did read somewhere I needed to add #Modifying and this will return an int or void. But when I try to test if it works I get a TransactionRequiredException error that says: Executing an update/delete query
Try using the below for update query
#Transactional
#Modifying(clearAutomatically = true)

Creating query exception in JPA while creting custom query method

JPA repository throwing Error for custom query method:
org.h2.jdbc.JdbcSQLException: Table "NBMRBANKDTLSENTITY" not found; SQL statement:
select NBMRBankDtlsEntity from NBMRBankDtlsEntity where NBMRBankDtlsEntity.ipphId = ? [42102-191]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
Class :
#Repository
public interface NBMRBankDtlsRepository extends JpaRepository<NBMRBankDtlsEntity, Long> {
#Query(value ="select n from NBMRBankDtlsEntity n where n.ipphId = :ipphId",nativeQuery = true)
Optional<NBMRBankDtlsEntity> findByIPPHId(#Param("ipphId") Long ipphId);
}
The error message tells you: Table "NBMRBANKDTLSENTITY" not found. Therefore it probably doesn't exist. To fix this you'll have to create the table, manually through a script or through hibernates schema creation feature.
I am already creating a table also inserting the record, After that only i am calling this custom query method.
I have found the issue as i am using nativeQuery = true so it is expecting normal sql query to query DB directly not the java query which is creating issue. Now after changing below it works fine ,
#Query(value = "SELECT * from NB_MR_BANK_DTLS WHERE IPPH_ID = :ipphId",nativeQuery = true)
For java query we can use directly as it internally converts to SQL while querying the DB,
#Query(value = "select p from NBMRBankDtlsEntity p WHERE p.ipphId = :ipphId")

Select Top 1 records from MS SQL using Spring Data JPA

I am using the below #Query annotation to get the first few record from MS-SQL. It's showing error saying "< operator > or AS expected..."
#Query("SELECT Top 1 * FROM NEVS010_VEH_ACTV_COMMAND C WHERE C.EVS014_VIN = :vin ORDER BY C.EVS010_CREATE_S DESC")
CommandStatus findCommandStatusByVinOrderByCreatedTimestampDesc(#Param("vin") String vin);
You can also use findFirst and findTop as mentioned in the Docs:
findFirstByVinOrderByCreatedTimestampDesc(String vin)
Since the query is SQL (and not JPQL) one needs to set nativeQuery = true in the annotation:
#Query(nativeQuery = true, value = "SELECT Top 1 * FROM NEVS010_VEH_ACTV_COMMAND C WHERE C.EVS014_VIN = :vin ORDER BY C.EVS010_CREATE_S DESC")
CommandStatus findCommandStatusByVinOrderByCreatedTimestampDesc(#Param("vin") String vin);
For custom Queries without using nativeQuery, the field ROWNUM can be used.
Ex (in Kotlin but the same idea works in Java):
#Query("""
SELECT a
FROM Account a
WHERE a.bla = :ble
AND ROWNUM = 1
ORDER BY a.modifiedDate DESC
""")
fun findWhatever(#Param("ble") someParam: String)
I haven't found that on any doc so far. I just tested and it worked for Oracle, MySQL and H2

org.postgresql.util.PSQLException: No results were returned by the query [duplicate]

I am trying to insert a data into a table. After executing the query i am getting an exception stating
org.postgresql.util.PSQLException: No results were returned by the query.
org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:284)
The data is getting inserted successfully, but i have no idea why i am getting this exception ??
Use
executeUpdate
instead of
executeQuery
if no data will be returned (i.e. a non-SELECT operation).
Please use #Modifying annotation over the #Query annotation.
#Modifying
#Query(value = "UPDATE Users set coins_balance = coins_balance + :coinsToAddOrRemove where user_id = :user_id", nativeQuery = true)
int updateCoinsBalance(#Param("user_id") Long userId, #Param("coinsToAddOrRemove") Integer coinsToAddOrRemove);
The same is true for any DML query (i.e. DELETE, UPDATE or INSERT)
Using #Modifying and #Transaction fixed me
The problem that brought me to this question was a bit different - I was getting this error when deleting rows using an interface-based Spring JPA Repository. The cause was that my method signature was supposed to return some results:
#Modifying
#Query(value = "DELETE FROM table t WHERE t.some_id IN (:someIds)", nativeQuery = true)
List<Long> deleteBySomeIdIn(#Param("someIds") Collection<Long> someIds);
Changing the return type to void resolved the issue:
#Modifying
#Query(value = "DELETE FROM table t WHERE t.some_id IN (:someIds)", nativeQuery = true)
void deleteBySomeIdIn(#Param("someIds") Collection<Long> someIds);
If you want last generated id, you can use this code after using executeUpdate() method
int update = statement.executeUpdate()
ResultSet rs = statement.getGeneratedKeys();
if (rs != null && rs.next()) {
key = rs.getLong(1);
}
I have solved this Problem using addBatch and executeBatch as following:
statement.addBatch("DELETE FROM public.session_event WHERE id = " + entry.getKey());
statement.executeBatch();

Ebean query using setDistinct() does not work

I'm using an ebean query in the play! framework to find a list of records based on a distinct column. It seems like a pretty simple query but the problem is the ebean method setDistinct(true) isn't actually setting the query to distinct.
My query is:
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findList();
In my results I get duplicate artist names.
From what I've seen I believe this is the correct syntax but I could be wrong. I'd appreciate any help. Thank you.
I just faced the same issue out of the blue and can not figure it out. As hfs said its been fixed in a later version but if you are stuck for a while you can use
findSet()
So in your example use
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findSet();
According to issue #158: Add support for using setDistinct (by excluding id property from generated sql) on the Ebean bug tracker, the problem is that an ID column is added to the beginning of the select query implicitly. That makes the distinct keyword act on the ID column, which will always be distinct.
This is supposed to be fixed in Ebean 4.1.2.
As an alternative you can use a native SQL query (SqlQuery).
The mechanism is described here:
https://ebean-orm.github.io/apidocs/com/avaje/ebean/SqlQuery.html
This is from the documentation:
public interface SqlQuery
extends Serializable
Query object for performing native SQL queries that return SqlRow's.
Firstly note that you can use your own sql queries with entity beans by using the SqlSelect annotation. This should be your first approach when wanting to use your own SQL queries.
If ORM Mapping is too tight and constraining for your problem then SqlQuery could be a good approach.
The returned SqlRow objects are similar to a LinkedHashMap with some type conversion support added.
// its typically a good idea to use a named query
// and put the sql in the orm.xml instead of in your code
String sql = "select id, name from customer where name like :name and status_code = :status";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
sqlQuery.setParameter("name", "Acme%");
sqlQuery.setParameter("status", "ACTIVE");
// execute the query returning a List of MapBean objects
List<SqlRow> list = sqlQuery.findList();
i have a solution for it:-
RawSql rawSql = RawSqlBuilder
.parse("SELECT distinct CASE WHEN PARENT_EQUIPMENT_NUMBER IS NULL THEN EQUIPMENT_NUMBER ELSE PARENT_EQUIPMENT_NUMBER END AS PARENT_EQUIPMENT_NUMBER " +
"FROM TOOLS_DETAILS").create();
Query<ToolsDetail> query = Ebean.find(ToolsDetail.class);
ExpressionList<ToolsDetail> expressionList = query.setRawSql(rawSql).where();//ToolsDetail.find.where();
if (StringUtils.isNotBlank(sortBy)) {
if (StringUtils.isNotBlank(sortMode) && sortMode.equals("descending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
//expressionList.orderBy().asc(sortBy);
}else if (StringUtils.isNotBlank(sortMode) && sortMode.equals("ascending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"asc");
// expressionList.orderBy().asc(sortBy);
} else {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
}
}
if (StringUtils.isNotBlank(fullTextSearch)) {
fullTextSearch = fullTextSearch.replaceAll("\\*","%");
expressionList.disjunction()
.ilike("customerSerialNumber", fullTextSearch)
.ilike("organizationalReference", fullTextSearch)
.ilike("costCentre", fullTextSearch)
.ilike("inventoryKey", fullTextSearch)
.ilike("toolType", fullTextSearch);
}
//add filters for date range
String fromContractStartdate = Controller.request().getQueryString("fm_contract_start_date_from");
String toContractStartdate = Controller.request().getQueryString("fm_contract_start_date_to");
String fromContractEndtdate = Controller.request().getQueryString("fm_contract_end_date_from");
String toContractEnddate = Controller.request().getQueryString("fm_contract_end_date_to");
if(StringUtils.isNotBlank(fromContractStartdate) && StringUtils.isNotBlank(toContractStartdate))
{
Date fromSqlStartDate=new Date(AppUtils.convertStringToDate(fromContractStartdate).getTime());
Date toSqlStartDate=new Date(AppUtils.convertStringToDate(toContractStartdate).getTime());
expressionList.between("fmContractStartDate",fromSqlStartDate,toSqlStartDate);
}if(StringUtils.isNotBlank(fromContractEndtdate) && StringUtils.isNotBlank(toContractEnddate))
{
Date fromSqlEndDate=new Date(AppUtils.convertStringToDate(fromContractEndtdate).getTime());
Date toSqlEndDate=new Date(AppUtils.convertStringToDate(toContractEnddate).getTime());
expressionList.between("fmContractEndDate",fromSqlEndDate,toSqlEndDate);
}
PagedList pagedList = ToolsQueryFilter.getFilter().applyFilters(expressionList).findPagedList(pageNo-1, pageSize);
ToolsListCount toolsListCount = new ToolsListCount();
toolsListCount.setList(pagedList.getList());
toolsListCount.setCount(pagedList.getTotalRowCount());
return toolsListCount;

Categories