Spring JPA Repository generating incorrect SQL - spring

I'm using Spring JPA Repository with Hibernate below towards a MySQL Database. On that environment, I've the following Entity:
#Entity
#Table(name="cod__postales")
public class CodigoPostal {
#Id
#GeneratedValue
private Long registro;
#Column(name = "`POST_Nº_CODIGO`", length = 6, nullable = false)
private String codigo = " ";
#Column(name = "POST_DESCRIP", length = 30, nullable = false)
private String descripcion = " ";
#Column(name = "POST_ZONA_ASIG", length = 2, nullable = false)
private String zona = " ";
Also I've the following Spring JPA Repository:
public interface CodigoPostalRepository extends JpaRepository<CodigoPostal, Long> {
CodigoPostal findOneByCodigo(String codigo);
}
As you can see, there isan special character on the first column name 'º'. The problem es that, when I call to repo.findOneByCodigo() method, the following SQL is generated
select codigopost0_.registro as registro1_2_,
codigopost0_.`post_nº_codigo` as post_nº_2_2_,
codigopost0_.post_descrip as post_des3_2_,
codigopost0_.post_zona_asig as post_zon4_2_
from cod__postales codigopost0_
where codigopost0_.`post_nº_codigo`=?
The problem is that sql gives an error because of the name spring/hibernate assing to that column: as post_nº_2_2_.
How can I avoid this?

This is a first thought regarding this query and my suggestion is to introduce a native query which will help you to change 'as post_nº_2_2_.' in something like: 'as post_n_2_2_.'.
Example:
#Query(value = " select codigopost0_.registro as registro1_2_,
codigopost0_.`post_nº_codigo` as post_n_2_2_,
codigopost0_.post_descrip as post_des3_2_,
codigopost0_.post_zona_asig as post_zon4_2_
from cod__postales codigopost0_
where codigopost0_.`post_nº_codigo`=?", nativeQuery = true)
public interface CodigoPostalRepository extends JpaRepository<CodigoPostal, Long> {
CodigoPostal findOneByCodigo(String codigo);
}
More information on this link.

At the end I've been able to solve this by adding the characterEncoding parameter to the url string:
spring.datasource.url=jdbc:mysql://localhost/madr?characterEncoding=UTF-8
Anyway, I've opened an issue to Hibernate because maybe this is not a valid option for everyone https://hibernate.atlassian.net/browse/HHH-10493

Change
#Column(name = "`POST_Nº_CODIGO`", length = 6, nullable = false)
to
#Column(name = "`POST_N_CODIGO`", length = 6, nullable = false)

Related

HQL Expects java.time.duration even though method-head and usage suggest LocalDateTime

I am writing a query within a JpaRepository which takes a String and 3 LocalDateTimes as parameters. Within the query I first compare the String like an Id and afterwards I use a different Column of the corresponding Entity to create LocalDateTimes using appropriate operators for Hibernate 6.
The Application starts up normal but when i call the query I get the following Error:
Argument [2023-01-23T11:43:59] of type [java.time.LocalDateTime] did not match parameter type [java.time.Duration (n/a)]
The Argument obviously got parsed correctly by the Restcontroller but Hibernate does not seem to create the query as expected.
The following is the Code for the Repository and the query in question:
public interface ExchangePairRepository extends JpaRepository<MyEntity, Long> {
#Query("SELECT ep.unit FROM MyEntity ep WHERE ep.id= :id AND ((ep.context = 'start' AND ((ep.unit = 'day' AND (:start+ ep.duration day) > :now) "
+ "OR (ep.unit = 'month' AND (:start+ ep.duration month) > :now))) OR (ep.context = 'end' AND ((ep.unit = 'day' AND (:now + ep.duration day) > :end) "
+ "OR (ep.unit = 'month' AND (:now + ep.duration month) > :end)) ))")
List<String> findViable(#Param("matNrOrig") String id, #Param("start") LocalDateTime start, #Param("end") LocalDateTime end,
#Param("now") LocalDateTime now);
}
Below is the Entity which i being used for the query:
#Entity
#Table(name = "my_entity")
#Data
public class MyEntity{
(...)
#Column(name = "id_orig")
private String idOrig;
´
#Column(name = "id_target")
private String idTarget;
#Column(name = "context")
private String context;
#Column(name = "duration")
private int duration;
#Column(name = "unit")
private String unit;
}
Is this a bug or am I doing something wrong? Any help is much appreciated.
I am using Hibernate 6.1.6.Final and Spring Boot 3.0.1 with Java 17
Edit:
Casting the parameters within the query solved the problem for now, though it does not look very pretty. I will just wait for the bug being fixed in one of the next releases.
This is a bug in the new parameter type inference logic. I can reproduce with just this query:
session.createQuery("select :dt + 1 day")
.setParameter("dt", LocalDateTime.now())
.getSingleResult();
I have opened an issue for you here: https://hibernate.atlassian.net/browse/HHH-16102
UPDATE
The following workaround is very ugly, but works:
session.createQuery("select cast(:dt as LocalDateTime) + 1 day")
.setParameter("dt", LocalDateTime.now())
.getSingleResult();

Race Condition in Postgres SQL using Spring data JpaRepository

I am facing a wierd issue in my implementation where I am persisitng data to a PostgresSQL DB using Spring data JpaRepository
In my Entity class I have the below columns:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private int id;
#Column(name = "field1", nullable = false, length = 16)
private String field1;
#Column(name = "field2", nullable = false, length = 16)
private String field2;
#Column(name = "field3", nullable = false, length = 16)
private String field3;
I initially avoided declaring the fields above as composite since there were many fields to be dealt with as composite keys. I thought the java code check would do the trick in all scenarios
So basically, I have to maintain the uniqueness of each row based on field1,field2 and field3. That was the basic requirement for which I had checks in my java code that if any entry exists in the DB for the combination of field1,field2 and field3 then I used to throw java exceptions
No two rows can have these values repeating. All was good until the application was tested under some errorneous business scenarios which would never happen in production but got run by mistake
Whats happening now is that if 2 requests are triggered at the exact same instance with the exact same 3 fields above (through a script) then they both enter into the Database since both get the entry check as false
Would declaring all of them as one composite key resolve the situation?
You should define the unique constraint in your database in addition of JPA constraint.
#Entity
#Table(uniqueConstraints={
#UniqueConstraint(columnNames = {"field1", "field2", "field3"})
})
public class MyEntity {
...
}

oracle with spring boot not fetching by primary key

I have written a spring boot app with oracle db.
Below is my entiry class.
#Entity
public class SystemTypeLookup{
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Type(type = "uuid-char")
#Column(name = "ID", updatable = false, nullable = false)
protected UUID id;
#Column(name = "CODE")
private String code;
}
And in passing my own UUID as primary key value.
In oracle db ID is considered as RAW and the UUID stored in oracle is differently.
There is no - separation in oracle and all the UUID chars are in upper case.
When i try to find the entity using primary key it is not fetching the row with id. I'm always getting null.
#Resource(name = "coreRepository")
private ErpEntityRepository coreRepositoryBase;
SystemTypeLookup systemTypeLookup = coreRepositoryBase.findOne("WHERE o.id='"+id+"'", SystemTypeLookup.class);
when is pass 76c03cd9-3d96-40c5-8df9-aad8f2369453 as id value then the oracle will insert the id without '-' and all chars will be in upper case.
So how to solve this issue?
First of all you should use parameters in your query and second make sure that the id you are passing is of type UUID and not String.

Mongo #DBRef unique

My application uses Spring Boot / JPA / MongoDB.
I map my domain classes to MongoDB using
org.springframework.data.mongodb.core.mapping.Document;
org.springframework.data.mongodb.core.index.Indexed;
org.springframework.data.mongodb.core.mapping.DBRef;
All is well except when trying to make a DBRef unique :
#DBRef #Indexed(unique = true)
private User owner;
I have tried different combinations of #DBRef, #Indexed (unique=true) and cannot make the DBRef unique. I can make other field-types unique, such as 'name' in the following example
#Indexed(unique = true)
#Size(min = 2, max = 100)
#Column(length = 100)
private String name;
but cannot find how to make my DBRef field unique.
I'm coming from the Morphia side of mapping, but I'd try this:
#CompoundIndexes({
#CompoundIndex(name = "owner", def = "{'owner.id' : 1}", unique = true)
})

Hibernate tuple criteria queries

I am trying to create a query using hibernate following the example given in section 9.2 of chapter 9
The difference with my attempt is I am using spring MVC 3.0. Here is my Address class along with the method i created.
#RooJavaBean
#RooToString
#RooEntity
#RooJson
public class Address {
#NotNull
#Size(min = 1)
private String street1;
#Size(max = 100)
private String street2;
private String postalcode;
private String zipcode;
#NotNull
#ManyToOne
private City city;
#NotNull
#ManyToOne
private Country country;
#ManyToOne
private AddressType addressType;
#Transient
public static List<Tuple> jqgridAddresses(Long pID){
CriteriaBuilder builder = Address.entityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<Address> addressRoot = criteria.from( Address.class );
criteria.multiselect(addressRoot.get("id"), addressRoot.get("street1"), addressRoot.get("street2"));
criteria.where(builder.equal(addressRoot.<Set<Long>>get("id"), pID));
return Address.entityManager().createQuery( criteria ).getResultList();
}
}
The method called jqgridAddresses above is the focus. I opted not to use the "Path" because when I say something like Path idPath = addressRoot.get( Address_.id ); as in section 9.2 of the documentation, the PathAddress_.id stuff produces a compilation error.
The method above returns an empty list of type Tuple as its size is zero even when it should contain something. This suggests that the query failed. Can someone please advise me.
OK so i made some minor adjustments to my logic which is specific to my project, however, the following approach worked perfectly. Hope it hepls someone in need !
#Transient
public static List<Tuple> jqgridPersons(Boolean isStudent, String column, String orderType, int limitStart, int limitAmount){
CriteriaBuilder builder = Person.entityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<Person> personRoot = criteria.from(Person.class );
criteria.select(builder.tuple(personRoot.get("id"), personRoot.get("firstName"), personRoot.get("lastName"), personRoot.get("dateOfBirth"), personRoot.get("gender"), personRoot.get("maritalStatus")));
criteria.where(builder.equal( personRoot.get("isStudent"), true));
if(orderType.equals("desc")){
criteria.orderBy(builder.desc(personRoot.get(column)));
}else{
criteria.orderBy(builder.asc(personRoot.get(column)));
}
return Address.entityManager().createQuery( criteria ).setFirstResult(limitStart).setMaxResults(limitAmount).getResultList();
}

Resources