Hibernate insert doesn't work with custom native query - java

In a spring boot project and database SQL Server, I'm doing some inserts where I need to return the id of the record
I have a Entity with few fields:
public class PackGroupEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long group_id;
private String group;
private String remark;
private String description;
....
}
I simplified the insert just to ask the question.
I have an insert statement and I need to retrieve the id from the inserted record.
String query = String.format(
"insert into pack_group(group, remark, description ) " +
"values ( %s, %s, %s)", "a","b","c" );
Query q = entityManager.createNativeQuery(query );
BigInteger biid = (BigInteger) q.getSingleResult();
long id = biid.longValue();
And I get this error
com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
Based on this answer here that I can use returning id so I tried but:
String query = String.format(
"insert into pack_group(group, remark, description ) " +
"values ( %s, %s, %s ) returning group_id;", "a","b","c" );
Query q = entityManager.createNativeQuery(query );
BigInteger biid = (BigInteger) q.getSingleResult();
long id = biid.longValue();
but it throws an error
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near 'returning'.
Can someone help me, please?

This things is SQL Server does not support returning syntax.
If you want get id for inserted row - you should use keyword output
This is official docs for using output with INSERT statement:
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-ver15#a-using-output-into-with-a-simple-insert-statement
You can also see this answer with examples for different SQL Server version for C# (but query does not different for Java):
https://stackoverflow.com/a/18373524/16644196

SQLServer doesn't support the returning clause. Instead, use the output clause.
String query = String.format("INSERT INTO pack_group(group, remark, description) "
+ "OUTPUT INSERTED.group_id "
+ "VALUES( %s, %s, %s )", "a","b","c");

Related

hibernate native query inserting records in a loop with many-to-one relationship

I'm working on a spring boot project, there I have two tables that are related to each other with OneToMany relationship
public class PackGroupEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private Double qty;
private Integer packingNr;
#Temporal(TemporalType.TIMESTAMP)
private Date deliveredTime;
#OneToMany(mappedBy = "packGroup", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<PackArticlesEntity> packArticles= new ArrayList<>();
}
And
public class PackArticlesEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Double qty;
private Double confirmedName;
#Enumerated(EnumType.STRING)
private ArticleStatus status;
private Double weight;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pack_group_id")
private PackGroupEntity packGroup;
}
And I insert data on these two tables in a loop, first I group the articles by packing number for which I will create a PackGroup that has a list of articles:
Map<Integer, List<RecivedArticlesDTO >> groupedArticles =
recivedArticlesListDTO.stream().collect(Collectors.groupingBy(RecivedArticlesDTO::getPackingNr));
for (Map.Entry<Integer, List<RecivedArticlesDTO>> entry : groupedArticles.entrySet()) {
List<RecivedArticlesDTO > groups = entry.getValue();
PackGroupEntity packGroup = new PackGroupEntity();
packGroup.setPackingNr(entry.getKey())
//some manipulations and setting data for each field
List<PackArticlesEntity> listWithArticles = new ArrayList<>();
groups.forEach(pack -> {
PackArticlesEntity packArticle= new PackArticlesEntity();
packArticles.setQty(pack.getQty);
//some manipulations and setting data for each field
listWithArticles.add(packArticles);
}
packGroup.setPackArticles(listWithArticles);
// here I have to save the data using native query
packGroupService.savePackGroupData(packGroup);
}
In this way, it is so slow so I wanted to do it on the native query.
The problem is that I have many packGroups a many packArticles that needs to be saved. I was thinking to somehow do only one connection with DB to send the list of pack groups and pack articles to save, but I don't know how to do this on native queries. This here is just for one pack_group but yet I don't know how to pass packArticles on a native query since it's a list
#Query(value = "insert into pack_group " +
" (id,packing_nr, description, qty, deliveredTime, packArticles) " +
" values (1?, 2?, 3?, 4?, 5?, 6?)", nativeQuery = true)
void savePackGroupData(id, packing_nr, description, qty, packArticles);
Can someone help with this, please?
EDIT:
I want to return the id from insert on
String query = String.format("insert into pack_group(group, remark, description ) " +
"values ( %s, %s, %s)", "x","y","z" );
Query q = entityManager.createNativeQuery(query );
BigInteger biid = (BigInteger) q.getSingleResult();
long id = biid.longValue();
And I get this error com.microsoft.sqlserver.jdbc.SQLServerException: The statement did not return a result set.
To speed things up consider using batch updates. It can be a bit tricky with spring data to get it to work, but it do speed things up considerably when working.
See How to do bulk (multi row) inserts with JpaRepository?
If you wish more control over your insert statements then perhaps spring jdbc is a better option :How to do multiple inserts in database using spring JDBC Template batch?
This is an answer for 'I have a list of articles in which I have to use the reference id of the previous inserted pack group. Can you get that on SQL?' in comment.
You have Main and Detail table. And you want to insert Main first, and Detail second with Id of Main just inserted.
You can use output inserted of SQL Server to get only currently inserted rows.
And you can join it with string_split result to insert into Detail table.
Here's example.
create table Main (
Id int identity(1, 1),
Name nvarchar(50)
);
create table Detail (
MainId int,
Name nvarchar(50)
);
insert into Main (Name) values ('X'); -- To make new inserted Id starts with 2
declare #MainList nvarchar(1000) = 'A,B,C';
declare #DetailList nvarchar(1000) = 'A2,B2,C2';
declare #IdList table (
Seq int identity(1, 1),
Id int
);
-- Insert 3 rows, get all 3 Id using inserted, insert 3 Id to #IdList table
insert into Main (Name)
output inserted.Id into #IdList
select value from string_split(#MainList, ',');
-- Join #IdList table with string_split returned table with Seq
-- Seq of #IdList is auto generated by identity(1, 1)
-- Seq of string_split returned table generated by row_number()
insert into Detail (MainId, Name)
select m.Id MainId, d.value Name
from #IdList m
inner join
(select row_number() over (order by (select 1)) Seq, value
from string_split(#DetailList, ',')
) d
on m.Seq = d.Seq;
Result:
select * from Main;
select * from Detail;
Id Name
--------
1 X
2 A
3 B
4 C
MainId Name
------------
2 A2
3 B2
4 C2
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=30213ab0cd59fcb7f541c18c738d4dad

Need to write Spring Data JPA interface method for Query

How can i convert the following native into Spring Data JPA interface method :
#Query(nativeQuery = true,
value = " select count(*) from TABLE "
+ "where ( ColumOne =:xyz or ColumnTwo =:xyz ) "
+ "and STATUS_TX in ('On Hold')")
int countAllByStatusAndName(#Param("xyz") String xyx);
I have written as
Long countByStatusTXAndColumnOnOrColumnTwo (String status, String xyz) . But its not working
I specifically need that or condition between ColumnOne and ColumnTwo.
There seems to be a typo in the method name. ColumnOn instead of ColumnOne. Try Long countByStatusTXAndColumnOneOrColumnTwo (String status, String xyz)

org.postgresql.util.PSQLException: ERROR: column "id" does not exist - Java Web Service

I am developing a java web service that is deployed in wildly. It is connected to a postgresql database.
In this database, I have a table called xx_activity. In it there is a column called "id", which is also the primary key.
Here is the query used to create the table:
CREATE TABLE xx_activity
(
id serial NOT NULL,
baseitemid integer
);
to connect to this table, I use the following java code:
conn = postgresVoyateDBConnection();
query = conn.prepareStatement("select id, baseitemid" +
"from xx_activity " +
"where \"id\" = ? ");
query.setInt(1, id);
ResultSet rs = query.executeQuery();
However, when I call the method that includes this code, I get an error:
org.postgresql.util.PSQLException: ERROR: column "id" does not exist
Position: 8
This is confusing because I certainly have this column. i added escape characters as per this answer, but it did not solve the issue.
Also note that queries without the where clause, like:
conn = postgresVoyateDBConnection();
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity");
ResultSet rs = query.executeQuery();
work perfectly.
I have also tried without using escape characters but it gives the same error. I also checked in pgadmin and there is no trailing space in the column name, neither are there any upper case letters involved (in which case, the other select query shouldn't have worked?).
How can this be fixed?
Fixed this, the issue was a missing space. After the first line of the query, there needs to be a space as belows:
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity " +
"where \"id\" = ? ");
EDIT: escape charactors not needed for id; so final answer should be:
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity " +
"where id = ? ");

Malformed query using IN

I have this structure:
public enum SaleItemType {
CRUISE,
DAILY_HOSTING
}
public class Estimate {
...
private List<SaleItemType> interestedSaleItemTypes;
#Column(name = "sale_item_type")
#CollectionTable(name = "estimate_sale_item_type", joinColumns = #JoinColumn(name = "estimate_id"))
#ElementCollection(targetClass = SaleItemType.class)
#Enumerated(EnumType.STRING)
public List<SaleItemType> getInterestedSaleItemTypes() {
return interestedSaleItemTypes;
}
}
And i'm trying to do a simple query:
String q = "FROM " + Estimate.class.getSimpleName() + " e" + " WHERE e.interestedSaleItemTypes IN :a";
TypedQuery<Estimate> query1 = getEm().createQuery(q, Estimate.class);
query1.setParameter("a", EnumSet.of(SaleItemType.CRUISE));
query1.getResultList();
I'm getting this query(and error) on the log:
DEBUG SQL:92 - select estimate0_.id as id1_25_, estimate0_.average_ticket as average_2_25_, estimate0_.description as descript3_25_, estimate0_.end_date as end_date4_25_, estimate0_.pax_quantity as pax_quan5_25_, estimate0_.start_date as start_da6_25_ from estimate estimate0_ cross join estimate_sale_item_type interested1_ where estimate0_.id=interested1_.estimate_id and (. in (?))
DEBUG SqlExceptionHelper:124 - could not extract ResultSet [n/a]
org.postgresql.util.PSQLException: No value specified for parameter 1.
Why hibernate is doing this query?
Im using Hibernate 5.1 Final
The IN expression can be used to test if a value is in a collection but interestedSaleItemTypes is not a simple value but itself a collection. Therefore use MEMBER OF:
String q = "FROM Estimate e WHERE :a MEMBER OF e.interestedSaleItemTypes";
TypedQuery<Estimate> query1 = getEm().createQuery(q, Estimate.class);
query1.setParameter("a", SaleItemType.CRUISE);
Did you try to put parenthesis in your IN clause?
I don't know if it's required, but in all tutorials that I found, always had the parenthesis. http://www.postgresqltutorial.com/postgresql-in/
Also, as the IN clause is expecting a list of values you can use the setParameterList instead of setParameter.
Try this:
String q = "FROM " + Estimate.class.getSimpleName() + " e" + " WHERE e.interestedSaleItemTypes IN (:a)";
TypedQuery<Estimate> query1 = getEm().createQuery(q, Estimate.class);
query1.setParameterList("a", EnumSet.of(SaleItemType.CRUISE));
query1.getResultList();

Update a column using hibernate

I have two classes Employee and Department.
public class Employee {
int empId;
String empName;
Boolean isEmpAvailable;
String empAddress;
Department department;
}
public class Department {
int deptId;
String deptName;
}
I have created hibernate files files for both classes Department.hbm.xml and Employee.hbm.xml
I like to update the column isEmpAvailable in the table Employee basing on a deptid in Department table.
Here I am facing problem with update query which I am not clear after reading in online documentation
public void updateEmployee(Employee emp, Department deptid){
String query= " update Employee set isEmpAvailable=? where deptid=?
Object[] values= {"true","133"};
getHibernateTemplate.update(query,values);
}
When i run the code the column doesn't get update. A error is thrown as
Entity not recognized: update Employee set isEmpAvailable=? where deptid=?
I have read online docs which have methods of getHibernateTemplate() which have return type as integer. Here I like to update the database directy by calling dao.updateEmployee without any returntype. I am unable do it. Please suggest me
Update in hibernate is done this way :
String hqlUpdate =
"update Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = session.createQuery( hqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
OR
String jpqlUpdate =
"update Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = entityManager.createQuery( jpqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
OR
String hqlVersionedUpdate =
"update versioned Employee e " +
"set e.isEmpAvailable = :isEmpAvailable " +
"where e.deptid = :deptid";
int updatedEntities = s.createQuery( hqlUpdate )
.setBoolean( "isEmpAvailable", isEmpAvailable )
.setInt( "deptid", deptid )
.executeUpdate();
If you want you can also use the saveOrUpdate() function. In this link there is an example and some documentation.

Categories