I am trying to map the result of an exists query (which returns TRUE/FALSE) from a MySQL database to a POJO via resultSetTransformer. I would hope the result of this exists query can get mapped to a boolean but it does not and throws the below error:
org.hibernate.PropertyAccessException: IllegalArgumentException
occurred while calling setter of TestBean.value
The cause of this exception is shown as:
java.lang.IllegalArgumentException: argument type mismatch
My sample class:
public class TestHibernate {
private static SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
public static void main(String[] args) throws ParseException {
try {
Query query = sessionFactory.openSession().createSQLQuery(
"SELECT " +
"EXISTS (SELECT * FROM A WHERE id = 3) AS value"
);
query.setResultTransformer(Transformers.aliasToBean(TestBean.class));
List<TestBean> beanList = (List<TestBean>) query.list();
} catch (Exception e) {
System.out.println(e);
}
}
}
The POJO:
public class TestBean {
private boolean value;
public boolean isValue() {
return value;
}
public void setValue(boolean value) {
this.value = value;
}
}
Am I missing something or is it a bug with Hibernate or MySQL JDBC Driver?
Hibernate version: 3.2.6GA
MySQL JDBC Driver: mysql-connector-java-5.1.2
Hibernate has a built-in "yes_no" type that would do what you want. It maps to a CHAR(1) column in the database.
Basic mapping:
<property name="some_flag" type="yes_no"/>
Annotation mapping (Hibernate extensions):
#Type(type="yes_no")
public boolean getFlag();
Your problem may be caused by the case mapping of the selected column, q.v. my solution below. I also parametrized your WHERE clause to avoid SQL injection.
Query query = session.createSQLQuery("select exists(select * from A where id = :id) as value");
.setParameter("id", "3");
.addScalar("value")
.setResultTransformer( Transformers.aliasToBean(TestBean.class))
List result = query.list();
TestBean theBean = (TestBean)result.get(0);
The transform of the result query can be explicitly set each parameter to the corresponding model datatype using hibernate addScalar() method. Please find the solution below.
Query query = sessionFactory.openSession().createSQLQuery(""+
"select " +
" exists(select * from A where id = 3) as value"
).addScalar("value", BooleanType.INSTANCE);
This will resolve to set to the Boolean value.
I know this is old answer, I tried to resolve this coz answer from here not worked for me.
with Addition to Answer from #anil bk, I overloaded a setter method accepting String as argument. Now It worked as expected.
public void setPriority(String priority) {
this.priority = "true".equals(priority);
}
Here is my answer
Related
Hi I am not able to update msgFromUserFlag in database through hibernate. Neither i am getting any error while updating this value.
This is my code at DAO layer. and in database my field is of TINYINT(1) type and in persistence class it is of type boolean.
public void updateMsgFromUserFlag(CustomerOrder customerOrderEntity){
try {
//update(customerOrderEntity);
final StringBuffer queryString = new StringBuffer("update CustomerOrder custOrder set custOrder.msgFromUserFlag = :param1 where custOrder.goldOrderNumber = :param2");
final Query query = this.getEm().createQuery(queryString.toString());
query.setParameter("param1",customerOrderEntity.isMsgFromUserFlag());
query.setParameter("param2", customerOrderEntity.getGoldOrderNumber());
int modification=query.executeUpdate();
}
catch(PersistenceException ex) {
otLogger.debug("OrderDaoImpl.exception occurred "+ex);
throw new TechnicalException(Constants.ERROR_HIBERNATE_EXCEPTION, ex);
}
}
I think your property is something like
private boolean msgFromUserFlag=false;
and the getters and setters were produced by eclipse itself, which will generate them like
public boolean isMsgFromUserFlag() {
return msgFromUserFlag;
}
public void setMsgFromUserFlag(boolean msgFromUserFlag) {
this.msgFromUserFlag = msgFromUserFlag;
}
You can try changing the getter to getMsgFromUserFlag(), because wrong getter methods sometimes causes Mapping Exception while publishing the project.
I am using the below hibernate code to fetch the data from database.
SessionFactory factory = null;
Session session = null;
try {
factory = getSessionFactory();
session = factory.openSession();
final Criteria criteria = session
.createCriteria(CrfEmailDataBean.class);
criteria.add(Restrictions.eq(CAMPN_NBR, campNbr));
returnList = criteria.list();
} catch (Exception e) {
logger.error(e.getMessage());
throw new DAOException(e);
} finally {
DBUtil.close(factory, session);
}
if (logger.isInfoEnabled()) {
logger.info(LOG_METHOD_EXIT);
}
return returnList;
}
Inside CrfEmailDataBean class, I have declared a private String crfEmailTypeCd; field which is null in database. Because of null, it is not setting the record in return list. If I go and enter a value inside the field in database, it fetches.
I tried running the query directly on sql database, the query formed is correct and fetches all the data.
Why it is not fetching that record? and how can I resolve this?
when you use type properties primitive same, need set the default value, same zero (0) or (a) ( ..)
private int number;
private int value;
private char option;
if hibernate database ready null, when converters of the Hibernate generator a error
solution for this never user primitive type
Or define de default value for properties
Each other possibility your date not null, this value white
white is different of the null
make a test put conditions Restrictions.isNotNull.
make other test put conditions Restrictions.isNull.
other test make a method receive int, call send one Integer null
first item
private Integer number;
private Integer value;
private Character option;
last item test
public class Test{
public static void setInt(int value){
System.out.println(value);
}
public static void main(String[] args)
{
Integer testValue=null;
Test.setInt(testValue);
} }
I'm using Hibernate and QueryDSL along with PostgreSQL on a Spring application, and face some performance issues with my filtered lists. Using the StringPath class, I'm calling either startsWithIgnoreCase, endsWithIgnoreCase or containsIgnoreCase.
It appears the generated query has the following where clause :
WHERE lower(person.firstname) LIKE ? ESCAPE '!'
Using the lower, the query is not taking advantage of the Postgres indexes. On a dev Database, queries take up to 1sec instead of 10ms with the ILIKE keyword.
Is there a way to get a Predicate using Postgres' ILIKE, as Ops doesn't seem to provide it?
Thanks
I've got exactly the same issue - lower(column) causes wrong pg statistics calculation and request is planned not efficiently, ilike solves the problem. I hadn't understood what parts of OP's answer are relevant to solution so reinvented the same approach, but a bit shorter.
Introduce new dialect with my_ilike function and it's implementation:
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL9Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new SQLFunctionTemplate(BooleanType.INSTANCE, "(?1 ilike ?2)"));
}
}
Specify this dialect to be used by Hibernate (I use Java config):
Properties props = new Properties();
props.setProperty("hibernate.dialect", "com.example.ExtendedPostgresDialect");
factory.setJpaProperties(props);
That's it, now you can use it:
BooleanTemplate.create("function('my_ilike', {0}, {%1%})", stringPath, value).isTrue();
Had to update this :
We found a way to create the needed Postgres operators by registering a SQL function using ilike, in our custom Hibernate Dialect.
Example with ilike :
//Postgres Constants Operators
public class PostgresOperators {
private static final String NS = PostgresOperators.class.getName();
public static final Operator<Boolean> ILIKE = new OperatorImpl<>(NS, "ILIKE");
}
//Custom JPQLTemplates
public class PostgresTemplates extends HQLTemplates {
public static final PostgresTemplates DEFAULT = new PostgresTemplates();
public PostgresTemplates() {
super();
add(PostgresOperators.ILIKE, "my_ilike({0},{1})");
}
}
Specify the JPQLTemplates when using jpaquery
new JPAQuery(entityManager, PostgresTemplates.DEFAULT);
now it gets tricky, we couldn't use ilike directly, there is an issue with an "ilike" keyword already registered, so we made an ilike function and registered it to a custom spring hibernate Dialect.
Our application.yml specifying :
#SEE JPA http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
spring.data.jpa:com.example.customDialect.config.database.ExtendedPostgresDialect
Then
public class ExtendedPostgresDialect extends org.hibernate.dialect.PostgreSQL82Dialect {
public ExtendedPostgresDialect() {
super();
registerFunction("my_ilike", new PostgreSQLIlikeFunction());
}
}
We tried to use the registerKeyword("ilike"), didn't work, we stayed with our function and the following implementation.
public class PostgreSQLIlikeFunction implements SQLFunction {
#Override
public Type getReturnType(Type columnType, Mapping mapping)
throws QueryException {
return new BooleanType();
}
#SuppressWarnings("unchecked")
#Override
public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) throws QueryException {
if (args.size() != 2) {
throw new IllegalArgumentException(
"The function must be passed 2 arguments");
}
String str1 = (String) args.get(0);
String str2 = (String) args.get(1);
return str1 + " ilike " + str2;
}
#Override
public boolean hasArguments() {
return true;
}
#Override
public boolean hasParenthesesIfNoArguments() {
return false;
}
}
That's pretty much it, now we can use ILIKE the following way :
BooleanOperation.create(PostgresOperators.ILIKE, expression1, expression2).isTrue()
I am having this strange issue where a sql query which is using Oracle Pivot syntax. I can run the query in SqlDeveloper with no issues; however, running it through JdbcTemplate with a RowMapper give this strange error about invalid column name.
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar ... nested exception is java.sql.SQLException: Invalid column name
SQL statement:
select * from (
Select stat.SWRHXML_HXPS_CODE
FROM Swbhxml xml
LEFT JOIN Swrhxml stat ON stat.swrhxml_trans_id = xml.SWBHXML_TRANS_ID
WHERE stat.SWRHXML_ACTIVITY_DATE = (
SELECT MAX(st.SWRHXML_ACTIVITY_DATE)
FROM swrhxml st
WHERE stat.SWRHXML_TRANS_ID = st.SWRHXML_TRANS_ID)
) pivot (count(SWRHXML_HXPS_CODE)
for SWRHXML_HXPS_CODE in
('NEW','EXPORT_READY','PENDING_MATCH','MATCHED_ID','PROCESSED','REJECTED'));
Row Mapper:
public class TranscriptStatusCountRowMapper implements RowMapper {
#Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
TranscriptStatusCounts tsc = new TranscriptStatusCounts();
tsc.setNewCount(rs.getLong("NEW_RECORDS"));
tsc.setExportReadyCount(rs.getLong("EXPORT_READY"));
tsc.setPendingMatchCount(rs.getLong("PENDING_MATCH"));
tsc.setMatchedIdCount(rs.getLong("MATCHED_ID"));
tsc.setProcessedCount(rs.getLong("PROCESSED"));
tsc.setRejectedCount(rs.getLong("REJECTED"));
return tsc;
}
}
DAO calling class:
#Repository("transcriptCountDao")
public class TranscriptCountDaoImpl extends BaseDaoImpl implements TranscriptCountDao {
private static final Logger logger = Logger.getLogger(TranscriptCountDaoImpl.class);
#Override
public TranscriptStatusCounts findTranscriptStatusCount() {
logger.debug("Getting counts of Transcripts status in system");
String sql = "...sql posted above..."
TranscriptStatusCounts tsc =
(TranscriptStatusCounts) getJdbcTemplate().queryForObject(sql, new TranscriptStatusCountRowMapper());
return tsc;
}
}
Ok... well I figured it out...
The Pivot table columns don't really map to well to my row mapper. So, I change the row mapper to the following which solved the issue:
TranscriptStatusCounts tsc = new TranscriptStatusCounts();
//'NEW','EXPORT_READY','PENDING_MATCH','MATCHED_ID','PROCESSED','REJECTED'
tsc.setNewCount(rs.getLong(1));
tsc.setExportReadyCount(rs.getLong(2));
tsc.setPendingMatchCount(rs.getLong(3));
tsc.setMatchedIdCount(rs.getLong(4));
tsc.setProcessedCount(rs.getLong(5));
tsc.setRejectedCount(rs.getLong(6));
return tsc;
I forgot that the sql "Invalid Column Name" error can also refer to the name used in the resultSet to access the column. Because the PIVOT query orders them, I can use just the number of the column to get back the results.
I am using Hibernate to map with MySQL
I have an entity class in which I have the methods mapped with columns in MySQL
The question is, if its possible that I do not map some of the method in that class with any column in SQL, as if i try not to map one of my method in entity class, it gives exception.
Here is the code snippet , what i am trying
#Column(name="skills")
public String getSkills() {
return skills;
}
public void setSkills(String skills) {
this.skills = skills;
}
#Transient
public int getRowCount() {
return rowCount;
}
public void setRowCount(int count) {
this.rowCount = count;
}
I have used #transiet , but after this if i set some value in setRowCunt and then tries to get that same value with getRowCount it gives null value , anyone have some idea
thanks
You are correct with the #Transient annotation. Perhaps you are setting the rowCount value in one object, than fetch it from db and try to get the value from it? - it would obviously fail because the field is not persisted and you're dealing with new instance of that object.
Perhaps You could provide broader context - what are the steps between setting a value and getting null?