hibernate can't detect named parameter - java

I am trying to execute a hibernate query. After I created the query, "query.getQueryString()"
prints like below:
select a
from com.mycompany.model.dwh.Instruction a
where a.custBillAcctId = :accountId
Then when I am trying to set parameter:
query.setParameter("accountId", new BigDecimal(accountId));
I get:
org.hibernate.QueryParameterException:
could not locate named parameter [accountId]
I print "query.getNamedParameters()", it seems empty. Hibernate somewhat can't detect :accountId. I tried different things, setting by parameter index, etc. All failed.
I did it millions of times in JEE-Hibernate, but I failed with Spring-Hibernate.
Environment: Eclipse-Jetty
hibernate: 4.1.9.Final
springframework: 3.2.1.RELEASE
#Entity
#Table(name = "TALIMAT")
public class Instruction implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "TALIMAT_ID")
#GenericGenerator(name="kaugen" , strategy="increment")
#GeneratedValue(generator="kaugen")
private Long key;
#Id
#Column(name = "CUST_BILL_ACCT_ID")
private BigDecimal custBillAcctId;
....
#Column(name = "STATUS")
private String status;
#Temporal(TemporalType.DATE)
#Column(name = "INSERT_DATE")
private Date insertDate;
Here is my code:
try {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("select a from " +
Instruction.class.getName() + " a
where a.custBillAcctId = :accountId ");
System.out.println("getNamedParameters: ");
for(String g:query.getNamedParameters()){
System.out.println(g + "\n");
}
query.setParameter("accountId", new BigDecimal(accountId));
} catch (Exception e1) {
e1.printStackTrace();
}
Thanks

I just solved the problem. It was a silly side-effect problem. I have multiple databaseContext.xml files each containing a datasources definition for a different database which application use. Although they are in seperate files, datasource id's were coinciding, this resulted in ambiguous behaviour.
When I gave them unique names, problem disappeared

Related

TypeMismatchException on fetching the table data by Hibernate Session.get() method

In a application, having a database table CUSTOMERS defined as:
create table CUSTOMERS (
ID varchar(10),
CODE varchar(10),
CID varchar(10),
SID varchar(10),
FNAME varchar(50),
LNAME varchar(50),
constraint PK_CUSTOMERS primary key (ID, CODE, CID, SID)
);
and the Entity classes are created to populate the data as
#Embeddable
public class CustKey implements Serializable , Cloneable{
#Transient
private static final long serialVersionUID = 1L;
#Column(name = "ID", nullable = false)
private String id;
#Column(name = "CODE", nullable = false)
private String code;
#Column(name = "CID", nullable = false)
private String cid;
#Column(name = "SID", nullable = false)
private String sid;
public boolean equals(Object o){
return id.equals(o.getId()) && ...;
}
public int hashcode(){
return id.hashcode() & ...;
}
}
#Entity
#Table(name = "CUSTOMERS")
public class CustProfileWrapper implements Serializable,Cloneable {
#Transient
private static final long serialVersionUID = 1L;
#EmbeddedId
private CustKey custKey;
#Column(name = "FNAME")
private String fname;
#Column(name = "LNAME")
private String lname;
}
The records are populated without an issue.
But the Entity classes are move to other project (but keeping the same package name as before) due to some rewrite of the code/project. but on fetching the data by Hibernate Session as
Object object = session.get(CustProfileWrapper.class, custProfileWrapper.getCustKey(), LockMode.NONE);
getting the error
org.hibernate.TypeMismatchException: Provided id of the wrong type for class CustProfileWrapper. Expected: class com.db.CustProfileWrapper, got class com.db.CustProfileWrapper
However, able to get the record when using the parametrized query as
SQLQuery query = session.createSQLQuery("SELECT * FROM CUSTOMERS WHERE ID = ? "
+ " AND CODE = ? AND CID = ? AND SID = ? ");
query.addEntity(CustProfileWrapper.class);
query.setParameter(0, "101");
...
object = query.list();
But it's a low level code when using the query, and we should use the
better way like get() method.
Any help/hint will be appreciated!!
Full stack trace of the error:
After so much investigation, found the culprit spring-boot-devtools dependency, as explained here:
I was getting this problem after adding a dependency to
spring-boot-devtools in my Springboot project. I removed the
dependency and the problem went away. My best guess at this point is
that spring-boot-devtools brings in a new classloader and that causes
the issue of class casting problems between different classloaders in
certain cases where the new classloader is not being used by some
threads.
Reference: A dozer map exception related to Spring boot devtools
Refs: ClassCastException when casting to the same class

JPA DB2 Native Query with Join Column

Here is my situation: I have a PrimeFaces application that is connecting to a DB2 database, and currently I am switching over JPQL queries to native SQL queries, because I need to be able to swap a schema programmatically for the same objects. With different native queries used to fetch from the DB2 database, a different schema can be used. However, I am running into an issue where one of the objects being fetched has a member with a #JoinColumn annotation.
The fetch of the main object seems to work fine, but when it tries to fetch the #JoinColumn member it fails, saying the table cannot be found using what I assume is some default schema. Consider the below classes:
#Entity
#Table(name = "MYOBJ1")
#NamedNativeQueries({
#NamedNativeQuery(name="MyObj1.findAll", query="SELECT * FROM SCHEMA1.MYOBJ1"),
#NamedNativeQuery(name="MyObj1.findAllAlt", query="SELECT * FROM SCHEMA2.MYOBJ1")
})
public class MyObj1 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
#OneToOne
#JoinColumn(name="obj2id", referencedColumnName = "id", insertable = false, updatable = false)
private MyObj2 myObj2;
// getters and setters
...
}
#Entity
#Table(name = "MYOBJ2")
#NamedNativeQueries({
#NamedNativeQuery(name="MyObj2.findAll", query="SELECT * FROM SCHEMA1.MYOBJ2"),
#NamedNativeQuery(name="MyObj2.findAllAlt", query="SELECT * FROM SCHEMA2.MYOBJ2")
})
public class MyObj2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
/// getters and setters
...
}
Running a native query like the below:
public MyObj1 getMyObj1(Integer id) {
Query query = em.createNativeQuery("SELECT * FROM " + ServerUtilities.getSchema() + ".MYOBJ1 WHERE " + ServerUtilities.getSchema() + ".MYOBJ1.id = '" + id + "'", MyObj1.class);
MyObj1 results = new MyObj1();
try {
results = (MyObj1) query.getSingleResult();
} catch (NoResultException e) {
results = null;
}
return results;
}
Yields this exception: java.sql.SQLException: [SQL0204] MYOBJ2 in MYAPPL type *FILE not found.
One option is to remove the #JoinColumn's, just store the foreign key and look up MyObj2 manually with separate SQL statements, but I am wondering if there is a better way to tell JPA which schema to use for #JoinColumn fetch statements at runtime.

Spring data jpa findByDate is always returning an empty list

I'm using in my application spring-data-jpa 1.9.2, mysql-connector 5.1 and hibernate 4.3.11 Final.
My Order class has a "creation" attribute of type date.
#Entity
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private java.util.Date creation;
}
In my JpaRepository I have these two methods to get the orders by date:
List<Order> findByCreation(Date date);
#Query("select o from Order o where o.creation = ?1")
List<Order> findByCreation2(Date date);
I'm not having an exception, but always an empty list, this can help you understand:
Date date = new Date();
Order order = new Order(date);
orderRepository.save(order);
Date creationFromDB = orderRepository.findOne(1L).getCreation();
System.out.println("eq? : "+ creationFromDB.equals(order.getCreation()));
List<Order> ods = orderRepository.findByCreation(creationFromDB);
List<Order> ods2 = orderRepository.findByCreation2(creationFromDB;
System.out.println("\n ods.size: " + ods.size() +", ods2.size: "+ods2.size());
The output is :
eq? : true
ods.size: 0, ods2.size: 0
NOTE
The select request had executed correctly and twice:
DEBUG org.hibernate.SQL - select order0_.id as id2_4_, order0_.creation as creation3_4_ from Orders order0_ where order0_.creation=?
What am I missing?
Did you generate your db scheme? Have you tried to generate it?
If it is possible to generate (with drop), set following property in your application.properties.
spring.jpa.hibernate.ddl-auto=create-drop
Potentially you have different data types (e.g. date vs. datetime) in you DB and used by spring data. I've recreated your project, and everithing worked fine whith H2 and MySQL.
EDIT:
Try to update your column description as follows:
#Column(name = "creation", columnDefinition="TIMESTAMP(6)")
#Temporal(TemporalType.TIMESTAMP)
private Date creation;
There might be different precisions. See my code:
Order class.
#Entity
#Table(name = "Ordr")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name = "creation", columnDefinition="TIMESTAMP(6)")
#Temporal(TemporalType.TIMESTAMP)
private Date creation;
// getters and setters
}
Test bean class.
#Component
public class SomeBean {
#Autowired
private OrderRepository orderRepository;
#PostConstruct
public void init() {
Date date = new Date();
Order order = new Order();
order.setId(1L);
order.setCreation(date);
orderRepository.save(order);
Date creationFromDB = orderRepository.findOne(1L).getCreation();
System.out.println("eq? : "+ new Date(creationFromDB.getTime()).equals(order.getCreation()));
List<Order> ods = orderRepository.findByCreation(creationFromDB);
List<Order> ods2 = orderRepository.findByCreation2(creationFromDB);
System.out.println("\n ods.size: " + ods.size() +", ods2.size: "+ods2.size());
}
}
Result:
eq? : true
ods.size: 1, ods2.size: 1
DB query:
mysql> select * from ordr;
+----+----------------------------+
| id | creation |
+----+----------------------------+
| 1 | 2016-08-03 15:15:12.386000 |
+----+----------------------------+
1 row in set (0,00 sec)
Looking at your code, I assume you are using java.util.Date. If so, use the following in the entity:
#Temporal(TemporalType.TIMESTAMP)
private Date creation;
if your column in the database is defined to be of type timestamp. If you are using pure date part in the column use TemporalType.DATE.
This is not required if you are using java.sql.Date.
I could be wrong:
You need describe "creation" property
#Column(name = "db_column_name")
private Date creation;
I recomennded use Timestamp in class and in DB too. Timestamp more useful.
I hope to help

Unable to locate appropriate constructor on class JPA

I am getting the following error:
java.lang.IllegalArgumentException: org.hibernate.QueryException: unexpected char:
SELECT NEW com.classes.applicant.ApplicantEntry(app.indSsn, app.indivName, app.indAddrLocTx,app.indAddrCityNm,app.indAdrStateAb,app.indAddrZipCd, app.phoneNr,app.workPhoneNr) FROM TApplicant app WHERE app.indSsn = :ssn
The class Constructor is correct:
public ApplicantEntry(String indSsn, String indivName, String indAddrLocTx, String indAddrCityNm, String indAdrStateAb, String indAddrZipCd,
String phoneNr, String workPhoneNr) {
this.indSsn = indSsn;
this.indivName = indivName;
this.indAddrLocTx = indAddrLocTx;
this.indAddrCityNm = indAddrCityNm;
this.indAdrStateAb = indAdrStateAb;
this.indAddrZipCd = indAddrZipCd;
this.phoneNr = phoneNr;
this.workPhoneNr = workPhoneNr;
}
And the entity:
#Entity
#Table(name = "T_APPLICANT", schema = "APP")
public class TApplicant implements Serializable, Applicant {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "IND_SSN", columnDefinition = "CHAR")
private String indSsn;
I do not understand why it is complaining about it is expecting all strings when it is recieving all strings.
I am running the query in intellij's persistence tool.
Full query in Repository:
#Query("SELECT NEW com.classes.applicant.ApplicantEntry(app.indSsn, app.indivName, "
+"app.indAddrLocTx,app.indAddrCityNm,app.indAdrStateAb,app.indAddrZipCd, app.phoneNr,app.workPhoneNr) "
+"FROM TApplicant app "
+"WHERE app.indSsn = :ssn ")
ApplicantEntry getApplicantEntry(#Param("ssn") String ssn);
Note for anyone using Lombok, the physical ordering of the fields in your class determines the order of your constructor parameters. The physical ordering of your class fields must match the ordering of the SELECT clause.
#AllArgsConstructor
public class Thing {
private String name;
private Date birthday;
}
// not the same as...
#AllArgsConstructor
public class Thing {
private Date birthday;
private String name;
}
ApplicantEntry constructor has 8 parameters while there are only 6 fields in the query.
The query doesn't look like correct jpa query. I think it should be
SELECT NEW org.classes.applicant.ApplicantEntry(
app.indSsn,
app.adnlPhysExamCd,
app.adnlPhysExamDt,
app.adultDepnQy,
app.adultDepnQy,
app.advRankRsnCd,
'placeholder',
'placeholder'
)
FROM ApplicantEntry app WHERE app.indSnn = :ssn

Validation not fired if I just clear an #OneToMany relation

I'm facing a problem when updating an Entity using JPA 2.0 and Hibernate (I didn't test with other providers). Here Is my entity (cutted down for brevity):
#Entity
public class CriterioDefinicaoImpFederais implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="criterio_definicao_imp_federais", sequenceName="criterio_definicao_imp_federais")
#GeneratedValue(generator="criterio_definicao_imp_federais", strategy=GenerationType.AUTO)
private Long id;
#Column(length=100)
#NotNull
#TextoValido(min=1, max=100)
private String descricao = "";
//Other fields ommited
#NotEmpty
#OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, mappedBy="criterio")
//Bidirectional association
private List<GrupoCriterioImpFederais> grupos = new ArrayList<>();
public Long getId() {
return id;
}
public void addGrupo(GrupoCriterioImpFederais grupo) {
grupo.setCriterio(this);
this.grupos.add(grupo);
}
public void removerGrupo(GrupoCriterioImpFederais grupo) {
grupos.remove(grupo);
grupo.setCriterio(null);
}
//Other methods ommited
}
Supose I try to persist one new CriterioDefinicaoImpFederais instance. Validation works well, including the #NotEmpty on field grupos.
Then I load the instance persisted, clear the grupos list (calling removerGrupo) and try to update (using the JPA 2.0 merge) the instance.
At this point, the validation for grupos (#NotEmpty) is not fired. BUT, if I change another field of CriterioDefinicaoImpFederais (like descricao for example), all validations are fired including the validations for grupos.
Is this the correct behavior? Or what am I missing? Is there a way to fire the validations?
Ps: I've tried to call flush after merge, without success.
Code to load and update objects:
To load I use the following hql:
//This is critRepo.porId
String sql = "select distinct c from CriterioDefinicaoImpFederais c "
+ " join fetch c.licenca "
+ " join fetch c.grupos g "
+ "where "
+ " c.id = :id ";
This is the code executed after the object is persisted:
em.getTransaction().begin();
CriterioDefinicaoImpFederais outro = critRepo.porId(criterio.getId());
em.getTransaction().commit();
em.clear();
outro.removerGrupo(outro.getGrupos().get(0));
outro.removerGrupo(outro.getGrupos().get(0));
em.getTransaction().begin();
//This method calls merge
critRepo.salvar(outro);
em.getTransaction().commit();
Thanks!
I haven't verified this, but it might be because you aren't accessing the value through an setter that adheres to the Java Bean Specification.
Try if you set it to a new empty collection through a normal setter.

Categories

Resources