Reputation: 2853
Im building a Spring Boot application which is auto configuring my JPA datasource based on the below properties.
spring.datasource.url=jdbc:jtds:sqlserver://localhost;DatabaseName=testDB;useCursors=true
spring.datasource.username=testDBUser
spring.datasource.password=test123
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.removeAbandoned=true
spring.datasource.removeAbandonedTimeout=300
spring.datasource.defaultTransactionIsolation=REPEATABLE_READ
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.use_query_cache=true
Now, I have a table as below
TableA{
String id;
String prop1;
String prop2;
String prop3;
}
The test case that fails is below. As you can see below I'm just trying to compare the result from EntityManager vs Spring Data Repository.
The test fails because the "id" value returned from EntityManager is "D97" (upper case) and the value returned from Spring Data repository is "d97". The actual value is "d97".
@Test
public void testIfSpringRepositoryWorks() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<TableAEntity> result = entityManager.createQuery("FROM TableAEntity WHERE id='d97'" , TableAEntity.class).getResultList();
if(result==null) {
Assert.fail("Empty Result from EntityManager for id: d97 ");
} else {
TableAEntity fromEntityManager = result.get(0);
TableAEntity fromSpringJPA = tableARepository.findOne("d97");
if(!fromEntityManager.equals(fromSpringJPA)) {
Assert.fail("TableAEntity is not same");
}
}
entityManager.getTransaction().commit();
entityManager.close();
}
I'm not sure on why EntityManager is converting my id field to upper case. Please help in finding out the root cause.
Thanks!
Upvotes: 0
Views: 1969
Reputation: 2853
I'm not sure if this is a problem or a situation for me to create a work around. But here's what is happening.
In the above test, my query to Spring JPA is
tableARepository.findOne("d97");
which is equivalent to
entityManager.find(TableA.class,"d97");
When either of both is executed, the below portion of the code forms the entity key in the Hibernate Row Reader logic (org.hibernate.loader.plan.exec.process.internal.RowSetProcessorHelper).
public static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SessionImplementor session) {
final Object optionalObject = queryParameters.getOptionalObject();
final Serializable optionalId = queryParameters.getOptionalId();
final String optionalEntityName = queryParameters.getOptionalEntityName();
return INSTANCE.interpretEntityKey( session, optionalEntityName, optionalId, optionalObject );
}
Needless to say, whatever parameter you pass as the key will ideally be the primary key value of the returned object (Ignoring the value returned by the database).
Now, when I execute the query
List<TableAEntity> result = entityManager.createQuery("FROM TableAEntity WHERE id='d97'" , TableAEntity.class).getResultList()
Since I'm not passing any primary key directly to hibernate its probably just retaining the value returned by hibernate.
Now as SQLServer default collation is case insensitive, it is capitalizing my primary key when it returns the data.
I'm not sure of the rationale behind why Hibernate overrides the value of primary key returned by the database.
But, it could be helpful if hibernate has a feature to turn off such a row processing logic.
Hope this helps!
Upvotes: 1