Using Postgres JSON function in Hibernate with injection - java

I am using Hibernate + SpringBoot and have a #Query() with nativeQuery=true where I am attempting to use a Postgres jsonb function to find a row where a JSON list has an entry with a specific field value, where banana_id is a parameter:
WHERE jsonb_path_exists(CAST(foo.things as jsonb), '$[*] ? (#.id == :banana_id)')
but no matter what I try, the query fails. According to this post Using Postgres JSONB query with Spring Data and bind parameter fails with InvalidDataAccessApiUsageException it's impossible to inject into a json path query, so that's why :banana_id doesn't work, but I can't figure out how to reframe this without that.

Ended up injecting the whole query as a string and casting it to jsonpath, with this:
jsonb_path_exists(CAST(foo.things as jsonb), CAST(:query_str as jsonpath))

Related

How can I replace using Query by Example in Spring Data JDBC?

In my view I send async request to controller with Json Data as following:
{
"filters":{
"someField":"someValue",
"someField":"someValue",
"someField":null,
"someField":null,
}
}
But data can be different.
And I have Order Entity that has same fields, so I can convert It from Json to POJO
After that using JPA I can do following:
Example<Order> orderExample = Example.of(orderFromJson);
orderRepository.findAll(orderExample);
But I use spring-data-jdbc which doesn't support it, What can replace it?
For cases like this where no direct support is offered, the correct approach is to get a JdbcTemplate or NamedParameterJdbcTemplate injected, and construct the required SQL from your filter information. You may make the method a custom repository method.

How to convert type from ObjectId to Long when using MongoTemplate?

Normally when using spring data repositories, an object in which the result data can be stored is needed like the customer in this example: https://spring.io/guides/gs/accessing-data-mongodb/ .
In my case I'm trying to use an object which is declared in another project I'm importing using maven - let's call it MyDoc. The object has an attribute Long id while the document in the MongoDB has an addition field _id from type ObjectId. This btw is like this because the MongoDB serves as an archive and the actual id from MyDoc would not be unique.
In a service class I then use this the MongoTemplate to make database queries like this:
List<MyDoc> list = template.findAll(MyDoc.class, "DOCS");
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.types.ObjectId] to type [java.lang.Long]
How can I convert the ObjectId to a type of Long?
Alternately, I could, of course, use the java MongoDB driver but I wanted to reduce the number of dependencies to maintain since the MongoDB driver comes with the boot-starter-data-MongoDB dependency, and also hoped for a more intuitive way, in the end, to interact with the database like with the spring data repositories.
First thing is Long Id from MyDoc is not unique, so it cannot act as _id of mongoDB.
Then you need to have one more _id field in your class. By Default Spring data mongoDB will map field named id to _id in dataBase.
Essentially what you can do is create a wrapper class around MyDoc by extending it and then add new field of Type ObjectId and annotate it with #Id. By that way you will have unique index and also mongoTemplate will not try to convert _id of database to Long id

Spring Boot: keywords supported for JPA

I wanted to perform the Spring JPA repository where wanted to apply the and operation among 2 columns where one column cloud have multiple values in it.
SQL query for the same:
select * from table_name where col1='col1_val' and col2 IN
('col2_val_a','col2_val_b','col2_val_c');
I know that for and operation I can extend the JpaRepository and create the method with like this for:
List<MyPoJoObject> findByCol1AndCol2(String col1_val,String col2_val);
and for IN operation we can use : findByCol2In(Collection<String> col2_val)
But i did not know how i can club both the mentioned JPA default method into one, as per my sql statement mentioned before.
You can use the following method named:
List<MyPoJoObject> findByCol1AndCol2In(String col1_val, Collection<String> col2_val);
On this link repository-query-keywords you can find repository query keywords that you can use and combine them as well.
You can certainly combined both into one method.
List<MyPoJoObject> findByCol1AndCol2In(String col1_val,String[] col2_val);
Try this. I am not sure if it will accept Collection<String>. I will try that and update the answer.
HTH.
If you want to perform this logic for more than two columns then your method name becomes verbose.
Instead of stuck with Spring naming why can't you write your own JPA query.
Example:
#Query("select pojo from MyPoJoObject as pojo where pojo.col1 = :col1_val and pojo.col2 in :col2_val")
List<MyPoJoObject> findByColumns(String col1_val, List<String> col2_val);

How to use Hibernate 5.2.10 MySQL JSON support without AttributeConverter or customUserType to map to Java Entity Class?

I am trying to map the MySQL JSON column to Java Entity class. Looking for the cleanest way of doing this.
Upon doing some research found 3 possible ways:
Extending AbstractSingleColumnStandardBasicType
Create a custom UserType
Use an attribute Converter
I used an attribute converter to convert the JSON column from String (as MySQL driver makes it to a String) to my required type - this works with both the Hibernate V4.3.10 and V5.2.10
I tried to find if JSON is natively supported in Hibernate and found the PR https://github.com/hibernate/hibernate-orm/pull/1395, based on the PR looks like it does add JSON mapping to the MySQL Dialect hence letting Hibernate know about the JSON Column.
Does this mean I can use something like this to map to JSON Column in DB ?#Column(name="json_type_column")
Private Object correspondingJsonAttribute;
If I cannot use it like this and need to use one of the above 3 methods, is there a reason I would need to upgrade to get the registerColumnType( Types.JAVA_OBJECT, "json" ); which is part of the PR and is present in Hibernate V5.2.10, Do I get any more features from V5.2.10 that support JSON columns?
I also looked into the corresponding test case to understand how the JSON column mapping is being done https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/access/MixedAccessTestTask.java, this uses #Access annotation via property, looks like it sets the corresponding JSON column variable in Entity to Map after converting it from String.
Any help is much appreciated.
Thanks!
Upon doing some research found 3 possible ways:
Extending AbstractSingleColumnStandardBasicType
Create a custom UserType
Use an attribute Converter
AttributeConvertor won't help you for this, but you can still use a custom UserType, or Hibernate Type Descriptors.
Does this mean I can use something like this to map to JSON Column in
DB?
#Column(name="json_type_column") Private Object
correspondingJsonAttribute;
No. The json type is just for JDBC so that Hibernate knows how to handle that JDBC object when setting a parameter on a PreparedStatement or when fetching a ResultSet.
Do I get any more features from V5.2.10 that support JSON columns?
No, but you just need to supply your own JSON type.
You can just use the hibernate-types which is available on Maven Central.
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
And use the provided JdonType from Hibernate Types as it works on MySQL, PostgreSQL, Oracle, SQL Server or H2 without doing any modifications.

Getting exception while accessing values from data base using hibernate

I have two tables website_availability and status_codes.And these have foriegn key relation between them.status_codes is parent table.I am using hibernate.I need "list" of values from these tables after joining.I am following this code.
List<WebsiteAvailability>list=new ArrayList<WebsiteAvailability>
String selquery="select w.statusCode,w.updateTime,w.statusCodes.statusCodeValue from WebsiteAvailability w,StatusCodes s where w.statusCodes.statusCode=s.statusCode and w.url=?";
//here hibernate generates the POJO classes and these are having foriegn key relation so WebsiteAvailability is having private StatusCodes statusCodes.So I am accessing statuscodevalue of statuscodes table using w.statusCodes.statusCodeValue.
PreparedStatement ps=con.prepareStatement(selquery);
ps.setString(1,selUrl);
rs=ps.executeQuery();
while(rs.next())
{
list.add(new WebsiteAvailability(rs.getString("statusCode"),rs.getTimestamp("updateTime"),rs.getString("statusCodeValue")));
}
return list;
}
First of all can I use resultset with hibernate.Is there any alternative for this.Because as I am using ? placeholder I should use preparedstatement for setString().And executeQuery() to get the list.I need list of values how can i get.Am getting empty list.What is the error?
org.hibernate.QueryException:could not resolve the property statusCode of -----WebsiteAvailability---
In the hibernate mapping file I have checked for case sensitivity.Still getting could not resolve property exception
You're trying to execute an HQL query, working on Hibernate entities, as a SQL query, using JDBC statements. That doesn't make sense. HQL queries are executed by the Hibernate Session. Not by JDBC. If you're using Hibernate, you don't need JDBC anymore (except maybe in some corner cases when you need raw JDBC performance, like batches).
Read the documentation about HQL query execution. You'll also have to fix your query, because it doesn't seem right. It contains w.statusCode and also w.statusCodes. It also does a join using equality statements and selects from two entities, instead of simply using implicit or explicit joins. Those are also explained in the documentation.

Categories

Resources