Add default value when field is null with MyBatis - java

I want to insert the default value from database when my field is null. I use an Oracle Database.
CREATE TABLE "EMPLOYEE"
("COL1" VARCHAR2(800) NOT NULL ENABLE,
"COL2" VARCHAR2(100) DEFAULT NOT NULL 'toto',
CONSTRAINT "PK_EMPLOYEE" PRIMARY KEY ("COL1")
with a simple SQL request, we can write:
insert into EMPLOYEE(COL1,COL2) values ('titi', default)
How can i do this with annotations MyBatis in Spring? I must create an HandlerType?

In mapper XML, build dynamically the SQL (add the col2 column and value when not null):
insert into employee (col1<if test="col2 != null">, col2</if>)
values (#{COL1}<if test="col2 != null">, #{col2}</if>)
EDIT: since value in annotation must be constant, I used to think dynamic SQl was not possible in annotation, but there is a trick I have found here: How to use dynamic SQL query in MyBatis with annotation(how to use selectProvider)? and checked it myself.
To use dynamic SQL this into an annotation, surround it with "script" tags:
#Insert("<script>insert into employee (col1<if test='col2 != null'>, col2</if>)
values (#{COL1}<if test='col2 != null'>, #{col2}</if>)</script>")
In tests, just escape double quotes " or replace them with simple quotes '

It should work if you omit the COL2 in your colum definition of the insert statement. Because the DB recognizes, that there is no value for the new row and it will apply the default value from the create table statement.
Have you tried something like this?
public interface EmployeeDAO {
String INSERT = "insert into employee (col1) values (#{COL1})";
#Insert(INSERT)
public int insertDefault(PersonDO p) throws Exception;
}

Related

Is there way to set default as null for SQL parameter?

I have a code that creates sql parameters using MapSqlParameterSource. Here is my code:
MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue(EVENT_ID, eventId)
.addValue(TYPE, type.toString())
.addValue(ACCOUNT_ID, null)
.addValue(USER_ID, null);
if (Type.SPOOFER_USER == type) {
parameters.addValue(USER_ID, account.getUser().getId());
}
else {
parameters.addValue(ACCOUNT_ID, account.getId());
}
Basically, if account type is spoofer, I have to have user id instead of account id. However, I don't like that I have to set account_id and user_id to null when I instantiate parameters. Is there way to set account_id and user_id as null so I don't have to write this two lines?:
MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue(EVENT_ID, eventId)
.addValue(TYPE, type.toString())
.addValue(ACCOUNT_ID, null) //////////////////////////THIS ONE
.addValue(USER_ID, null); //////////////////////////AND THIS ONE
Here is my sql query:
INSERT INTO database (id, event_id, type, account_id, user_id)
VALUES (database.nextval, :event_id, :type, :account_id, :user_id)
Update:
Maybe my question was not specific enough. What happens is that when I run
jdbcTemplate.update(insertEventExtra, parameters);
With the given parameters without making them "NULL", I get this exception in my unit test:
org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter 'user_id': No value registered for key 'user_id'
I use hsql to test it. my .sql looks like this:
...
ID NUMBER(38,0) PRIMARY KEY,
EVENT_ID BIGINT NOT NULL,
TYPE VARCHAR2(20 BYTE) NOT NULL,
ACCOUNT_ID NUMBER(38,0),
GROUP_ID NUMBER(38,0),
USER_ID NUMBER(38,0),
...
So my specific question is that my test is giving me exception when I try to run test with parameters without setting them to null.
You must include the addValue(ACCOUNT_ID, null) and addValue(USER_ID, null) because your INSERT statement includes the two named parameters :account_id, :user_id.
The framework attempts to extract the values for the named parameters from the MapSqlParameterSource object and when it does not find one of them, it throws the exception. It does this to avoid user errors, because if you didn't intend to provide a value for a parameter, you wouldn't include the parameter in the INSERT statement.
Make your columns nullable and default to null in the database schema. Then, if you don't specify a value for a column when inserting, it should default to null
By default all not null columns have default value of NULL unless and until you provide value while inserting or updating the column.

How can I handle null values in an INSERT with JPA?

I'm trying to execute an insert operation to an Oracle DB Table from Java with JPA.
The following is my code:
String coCode;
String coDescription;
/* some operations on data ... */
String queryStatement =
"insert into MANAGER_DATA (CO_CODE, CO_DESCRIPTION) values (?1, ?2)";
Query updateQuery = getEntityManager(context).createNativeQuery(queryStatement);
updateQuery.setParameter(1, coCode);
updateQuery.setParameter(2, coDescription.compareTo("") == 0 ? null : coDescription);
updateQuery.executeUpdate();
The problem is that coDescription can be null in case of an empty String and, in that case, I want the null value to be added in the table as well (coCode is primary key but coDescription is nullable). Apparently I cannot pass a null value to the setParameter function directly, as I am doing above.
How can I solve this and allow the null value to be added to my DB table?
Looks like you might be using old Hibernate version affected by HHH-9165 createNativeQuery's setParameter does not support null bug. Upgrade to Hibernate 5.0.2 or newer to resolve it. As per mentioned Jira:
Just tested it with Hibernate 5.0.2 and the bug seems to be resolved.
Oracle evaluates empty strings as null.
For example:
insert into MANAGER_DATA (CO_CODE, CO_DESCRIPTION) values ('my_code', '')
will insert this row: ('my_code', null).
Therefore you can leave it empty string.

iBatis insert statement throwing NPE

I am new to iBatis. In my project we are using iBatis to persist the java objects in Oracle DB. I have a class, ClassA, which is having 3 columns : id, name and description. The data is going to be persisted in TableA. There is a sequence in DB to generate the value for id column in this table. We wrote the insert statement to this table as follows,
<insert id="insertTableA" parameterClass="com.ClassA">
<selectKey resultClass="java.lang.Long" keyProperty="id">
SELECT seq_TableA.nextval as id FROM dual
</selectKey>
INSERT INTO TableA(ID, NAME, DESCRIPTION) VALUES (#id#, #name#, #description#)
</insert>
This worked fine.
But becaude of our inhouse UI framework limitation we had to change some design. So we need to first generate the id long from sequence, set that value in an instance of ClassA along with name and description and then insert into DB. So in that case the insert statment doesn not need a selectKey attribute. The id, name and description values are in the object. When I updated the query like below, it is throwing Null Pointer Exception.
<insert id="insertTableA" parameterClass="com.ClassA">
INSERT INTO TableA(ID, NAME, DESCRIPTION) VALUES (#id#, #name#, #description#)
</insert>
How we can insert data into table without using a . I am generating the key from the sequence first , populate the object with all values including the id and trying to call the statement from Java as follows,
getSqlTemplate().insert("process.insertTableA", instanceClassA);
Any pointers are welcome,
Thanks,
SD
Just to be sure, did you include a getId() method in your ClassA class so that it will return the value of the id field?

Hibernate issue - Invalid column name

I have added two columns in the sql to get the values through hibernate.My databse is oracle and those fields datatype i number. So i have created the beans with long and (tried Integer too) but when retrieving the values(executing the valuesquery).
Its giving me an error
org.hibernate.type.LongType - could not read column value from result set
java.sql.SQLException: Invalid column name
at oracle.jdbc.driver.OracleStatement.getColumnIndex(OracleStatement.java:3711)
at oracle.jdbc.driver.OracleResultSetImpl.findColumn(OracleResultSetImpl.java:2806)
at oracle.jdbc.driver.OracleResultSet.getLong(OracleResultSet.java:444)
at weblogic.jdbc.wrapper.ResultSet_oracle_jdbc_driver_OracleResultSetImpl.getLong(Unknown Source)
at org.hibernate.type.LongType.get(LongType.java:28)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:163)
at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:189)
tABLE DEFINITION :
CREATE TABLE "PRODUCTLIST"
(
PRICELIST_PUBLISH_KEY decimal(22) NOT NULL,
PRODUCT_NBR varchar2(54) NOT NULL,
PRODUCT_KEY decimal(22),
PRODUCT_DESCRIPTION varchar2(360),
PRODUCT_FAMILY_NBR varchar2(30),
PRODUCT_FAMILY_DESCR varchar2(180),
PRODUCT_GROUP_NBR varchar2(30),
PRODUCT_GROUP_DESCR varchar2(180),
PRODUCT_LINE_NBR varchar2(30),
PRODUCT_LINE_DESCR varchar2(180),
PRODUCT_CLASS_CODE varchar2(6),
LAST_PP_GENERATED_DATE_KEY decimal(22),
LAST_PP_GENERATED_DATE date,
PUBLISH_PERIOD_KEY decimal(22) NOT NULL,
PUBLISH_PERIOD_DATE date,
PL_KEY decimal(22),
PRODUCTLIST varchar2(750),
SALES_KEY decimal(22),
PRODUCT varchar2(60),
DM_EXTRACTED_BY_USER varchar2(90)
)
sql :
Query query = session.createSQLQuery(channelQuery)
.addScalar("PRODUCT",Hibernate.STRING)
.addScalar("PRODUCTLIST",Hibernate.STRING)
.addScalar("PRODUCTKEY",Hibernate.LONG)
.addScalar("SALESKEY",Hibernate.LONG)
.setResultTransformer(Transformers.aliasToBean(SearchResult.class));
return query.list();
}
});
Please help me to fix the issue ?
In your table definition, I can't see all the fields you're using in the addScalar() methods: there are no PRODUCTKEY nor SALESKEY fields. Instead I can see a PRODUCT_KEY and a SALES_KEY fields (underscores). I think you should use the correct name of the fields in the addScalar() methods.
But if your query is the one you put in your comments, you have to correct some details:
you should use p instead of pub as alias for the table name. As there is only one table in the query, you can suppress the alias.
In your SELECT clause, p.productprice is not an existing field in your table. Maybe you want to use p.pricelist instead.
In your WHERE clause, p.productnbr is not an existing field in your table. You should use p.product_nbr instead.
Then you should change the field names in the addScalar() methods to match those you are using in the query.
Modified query
SELECT distinct p.product, p.productlist, p.PL_KEY, p.SALES_KEY
FROM productlist p
WHERE p.product_nbr in ('1002102')
Your code should be:
Query query = session.createSQLQuery(channelQuery)
.addScalar("PRODUCT",Hibernate.STRING)
.addScalar("PRODUCTLIST",Hibernate.STRING)
.addScalar("PL_KEY",Hibernate.LONG)
.addScalar("SALES_KEY",Hibernate.LONG)
.setResultTransformer(Transformers.aliasToBean(SearchResult.class));
return query.list();
If you define aliases in your query, then you can use the alias names instead of the field names. For example, with this query:
SELECT distinct p.product, p.productlist, p.PL_KEY as PRODUCTKEY, p.SALES_KEY as SALESKEY
FROM productlist p
WHERE p.product_nbr in ('1002102')
you can use the following code (it's your original code):
Query query = session.createSQLQuery(channelQuery)
.addScalar("PRODUCT",Hibernate.STRING)
.addScalar("PRODUCTLIST",Hibernate.STRING)
.addScalar("PRODUCTKEY",Hibernate.LONG)
.addScalar("SALESKEY",Hibernate.LONG)
.setResultTransformer(Transformers.aliasToBean(SearchResult.class));
return query.list();

SQL update not working with integer ID

This command on SQL Server
UPDATE tbl SET name='Hi' WHERE id=''
works if 'id' is set as an integer value, but it does not work on H2.
What may be the solution?
If ID is integer, you shouldn't use quotes for the value:
UPDATE TEST SET NAME='Hi' WHERE ID = 5; // not ID = '5'
Many databases will accept the quoted version, but are not required to by the SQL language specification.
UPDATE TEST SET NAME='Hi' WHERE ID='1';
that is working in sql server even if id field is integer
but if you want to update the row where id is null then you have to use below statement :
UPDATE TEST SET NAME='Hi' WHERE ID is Null;
instead of UPDATE TEST SET NAME='Hi' WHERE ID ='';
And if id is varchar then you can use your statement to update the values where ID is not null and data is not available there.
But if you want to update the values for record where NULL value of ID field then you have to use
UPDATE TEST SET NAME='Hi' WHERE ID is Null;
H2 throws an exception because it can't convert the empty string '' to a number. H2 internally uses java.lang.Long.parseLong("") which fails with java.lang.NumberFormatException: For input string: "".
For the SQL script:
drop table tbl;
create table tbl(id int primary key, name varchar(255));
insert into tbl values(1, 'Hello');
UPDATE tbl SET name='Hi' WHERE id='';
H2 will throw the exception:
Data conversion error converting [22018-161]
Most other databases (PostgreSQL, Apache Derby, HSQLDB) throw a similar exception.
You need to use a number, or IS NULL as in:
UPDATE tbl SET name='Hi' WHERE id IS NULL;
or
UPDATE tbl SET name='Hi' WHERE id = 0;

Categories

Resources