Entity inheritance an error while refreshing with EntityManager - mysql

When using entity inheritance hierarchy witch #DiscriminatorColumn storing DiscriminatorType.STRING values in MySQL ENUM. Below code example:
#Entity
#DiscriminatorColumn(name ="account_type", discriminatorType = DiscriminatorType.STRING,
columnDefinition = "ENUM('natural_person', 'firm', 'provider', 'employee', 'administrator', 'moderator', 'user')")
#DiscriminatorValue("user")
public class User implements Serializable { ... }
and inherited entity:
#Entity
#DiscriminatorValue("firm")
public class Firm extends User { ... }
when I create Firm object or removes everything works ok, even when I find it with EntityManager, but if I make EnityManager.refresh(firm) than there is an error complaining about:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'firm0_.account_type' in 'field list'
UPDATE:
When I changed this columnDefinition of #DescriminatorColumn by deleting it and storing strings "firm", "user", ERROR ALSO OCCURES!
UPDATE 2:
I have a little suggestion that as Firm extends UserAccount this discriminator column account_type should be in user_account table. So error firm0.account_type seems stupid as it search this column in user_account.account_type!
I have another subclass Person and it persists and than saves OK, but Firm only persists, removes but DON'T REFRESH!
UPDATE 3:
Found sql log like this:
Hibernate:
insert
into
user_account
(activation_code, email, last_failed_login, last_logged, login, password, registration_date, account_type)
values
(?, ?, ?, ?, ?, ?, ?, 'firm')
Hibernate:
insert
into
firm
(address_city, address_country, address_office_no, address_building_no, address_state, address_street, address_zip_code, client_id, company_number, name, phone_number, skype_name, statistic_number, vatin, user_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
select
firm0_.user_id as user_id2_14_0_,
firm0_1_.activation_code as activati3_14_0_,
firm0_1_.email as email4_14_0_,
firm0_1_.last_failed_login as last_fai5_14_0_,
firm0_1_.last_logged as last_log6_14_0_,
firm0_1_.login as login7_14_0_,
firm0_1_.password as password8_14_0_,
firm0_1_.registration_date as registra9_14_0_,
firm0_.address_city as address_1_3_0_,
firm0_.address_country as address_2_3_0_,
firm0_.address_office_no as address_3_3_0_,
firm0_.address_building_no as address_4_3_0_,
firm0_.address_state as address_5_3_0_,
firm0_.address_zip_code as address_7_3_0_,
firm0_.client_id as client_15_3_0_,
firm0_.company_number as company_8_3_0_,
firm0_.name as name9_3_0_,
firm0_.skype_name as skype_n11_3_0_,
firm0_.statistic_number as statist12_3_0_,
firm0_.vatin as vatin13_3_0_,
firm0_2_.corporation_id as corporat5_8_0_,
firm0_2_.description as descript1_8_0_,
firm0_2_.name as name2_8_0_,
firm0_2_.type as type3_8_0_,
firm0_.account_type as account_1_14_0_
from
firm firm0_
inner join
user_account firm0_1_
on firm0_.user_id=firm0_1_.user_id
left outer join
provider firm0_2_
on firm0_.user_id=firm0_2_.provider_id
where
firm0_.user_id=?
Jun 10, 2015 5:37:16 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1054, SQLState: 42S22
Jun 10, 2015 5:37:16 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Unknown column 'firm0_.account_type' in 'field list'
Jun 10, 2015 5:37:16 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH000030: Cleaning up connection pool

I'm guessing that when JPA generates the DDL it is using the columnDefinition string as a literal for the column definition. Thus, it should be "account_type ENUM('natural_person', 'firm', 'provider', 'employee', 'administrator', 'moderator', 'user')"

Ok It seems I found solution but it is odd, and I will be testes it later.
private String accountType;
#Column(name = "account_type", insertable = false, updatable = false)
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
I have added this code into UserAccount (superclass - root of inheritance hierarchy), where discriminator column is defined... BUT it seems odd behaviour to define explicite discriminator column in entity! I read that it is anit-pattern, not recommanded to add, and moreover to use such discriminator column in code...

Related

How to get Date input value from thymeleaf to MySQL in Spring Boot Application Java?

I want to get input value from Spring Boot Application thymeleaf(HTML) to MySQL Database in format Date.
But I get this error message :
"Failed to convert value of type 'java.lang.String' to required type 'java.sql.Date'".
This is my Controller path code below. Thanks in advance.
#GetMapping("/saveApplication")
public String saveApplication(#RequestParam(name="name", required = false) String name,
#RequestParam(name="surname", required = false) String surname,
#RequestParam(name="place", required = false) String place,
#RequestParam(name="start", required = false) #DateTimeFormat(pattern = "dd.MM.yyyy") Date start,
#RequestParam(name="end", required = false) #DateTimeFormat(pattern = "dd.MM.yyyy") Date end,
#RequestParam(name="identity", required = false) Integer identity,
#RequestParam(name="tel", required = false) Integer tel,
Model model)
{
final Integer id = 1;
String sql = "INSERT INTO `user`.`application` (`kullaniciid`, `name`, `surname`, `place`,`start`, `end`,`identity`,`tel`) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(sql, id,name, surname, place,start, end,identity,tel);
return "screen3";
}
I fixed it change #DateTimeFormat to #Date and import Date.

Rollback transaction not working properly

In database manipulation command such as insert, update or delete can sometime throws exception due to invalid data. To protect the integrity of application data we must make sure when we a transaction was failed we must rollback
PreparedStatement ps = null;
Connection conn = null;
try {
conn = DriverManager.getConnection( URL, USERNAME, PASSWORD );
String query = "INSERT INTO tbl1(id, username) " +
"VALUES (?, ?)";
ps = conn.prepareStatement( query );
ps.setString( 1, "javaduke" );
ps.execute();
query = "INSERT INTO tbl2 (id, tbl1_id, " +
"quantity, price) VALUES (?, ?, ?, ?)";
ps = conn.prepareStatement( query );
ps.setInt( 1, id );
ps.setInt( 2, tbl_id );
ps.setInt( 3, 10 );
ps.setDouble( 4, 29.99 );
ps.execute();
}
catch ( SQLException e )
{
conn.rollback()
e.printStackTrace();
}
I guess this is Java.
Right after you get your connection object, turn off autocommit, like so.
conn = DriverManager.getConnection( URL, USERNAME, PASSWORD );
conn.setAutoCommit(false);
Right after your last execute() do this.
conn.commit();
Then the rollback() in your exception handler should do what you expect.
This should extend the scope of your transaction to beyond a single SQL query.

update some attributes of an object and return the whole object

I am trying to update a Customer password having his email, and after my update i want the ResponseEntity to return the whole Customer Object after modification is done.
But I am having this error into postman:
"error": "Internal Server Error",
"error_description": [
"could not execute batch; SQL [insert into tcustomer (authentication_uid, creation_date, attribute_uid, default_payment_method_uid, guid, last_edit_date, pref_bill_address_uid, pref_ship_address_uid, status, storecode, type, user_id, uidpk) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute batch"
]
I am passing a JSON with the the password and email:
{
"password": "miam",
"userId": "ton.nya#yahoo.fr"
}
here is the serviceImpl:
public CustomerDto updateCustomerPassword( String userId, String password) {
CustomerAuthentication customerAuthentication = new CustomerAuthentication();
customerAuthentication.setPassword(password);
Customer customer = new Customer();
customer.setAuthenticationUid(customerAuthentication);
customer.setUserId(userId);
Customer result = customerRepository.save(customer);
return customerMapper.customerToCustomerDto(result);
}
here is the ressource
#PutMapping(CUSTOMER_ENDPOINT)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
#ApiResponses(value = {
#ApiResponse(code = 201, message = "The Customer has been created", response = CustomerDto.class),
#ApiResponse(code = 204, message = "The Customer has been updated", response = CustomerDto.class),
#ApiResponse(code = 500, message = "Unexpected error")
})
#Timed
public ResponseEntity updateCustomer(final HttpServletRequest request, #RequestBody String userId, String password)throws MethodArgumentNotValidException{
log.debug("[CustomerResource] PUT {} Updating Customer", CUSTOMER_ENDPOINT);
CustomerDto result = customerService.updateCustomerPassword(userId,password);
log.debug("[CustomerResource] Customer ({}) Updated",result.getUidpk());
return new ResponseEntity<>(result,null, HttpStatus.NO_CONTENT);
}
Are there any other solution? Thanks.

HIbernate batch insert or update not working in spring boot

I need to do Bulk inserts(nearly 10000) in my MySQL database. I am using JPA/hibernate and spring boot. I read performing bulk insert/update in hibernate from hibernate documentation, I think my code is not working as it is sequentially inserting the hibernate queries instead of performing them in a batch insert. Below is my code. Am I missing something?
Here is my DataSource configuration.
#Component
public class Datasource {
#Autowired
EnvConfiguration configuration;
private static final Logger logger = LoggerFactory.getLogger(Datasource.class);
#Bean
public DataSource dataSource(){
logger.info("DataSource Bean creation...");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(configuration.getDBDriver());
dataSource.setUrl("jdbc:mysql://"+configuration.getDBIp()+":"+configuration.getDBPort()+"/"+configuration.getDBName()+"?autoReconnect=true&useSSL=false");
dataSource.setUsername(configuration.getDBUser());
dataSource.setPassword(configuration.getDBPass().trim());
return dataSource;
}
#Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
}
Code for my Role domain
//Role.java
#Entity
#Table(name = "Role",uniqueConstraints = #UniqueConstraint(
columnNames = { "roleName"}))
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long roleId;
#NotNull
private String roleName;
public Role(){}
public Role(String roleName){
this.roleName = roleName;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
}
Below is my service code. Here I am manually flushing the session. I have added a sleep function in order to find whether insert query executed one by one or they are executing in batch of 10 as happen in JDBC batch.
#Service
public class RoleService{
#Autowired
private SessionFactory factory;
#Autowired
private DataSource source;
private static final Logger logger = LoggerFactory.getLogger(WalletService.class);
public void insertRole(Collection<RegisterWallet> walletMetaCollection){
if(factory==null){
System.out.println("factory is null");
}else{
System.out.println("factory is working");
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Role role=new Role(""+i);
session.persist(role);
System.out.println("this is the role id "+role.getRoleId());
try {
Thread.sleep(1000);
} catch (InterruptedException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
if ( i % 10 == 0 ) { //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
}
}
}
As per my understanding over batch operation, 10 roles should be inserted at once, decreasing number of jdbc round trips used. But output of the above code is quiet unexpected. It is executing one insert per session.persist(..) call.
//This is log of the above code.
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 14
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 15
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 16
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 17
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 18
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 19
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 20
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 21
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 22
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 23
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 24
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 25
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 26
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 27
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 28
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 29
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 30
Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
this is the role id 31
</pre>
-------------------------------------------------------------
Following is my application.properties configuration
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
spring.jpa.properties.hibernate.jdbc.batch_size=10
Am I missing something?
Please help.
You are't missing anything.Your output is quite normal.You can get more info on this link: [1]http://www.dineshonjava.com/2012/06/hibernate-batch-processing_10.html

Prepared Statement INSERT JDBC MySQL

I am getting an error on doing ' mvn tomcat:run " . The error I am getting is:
exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [INSERT INTO ibstechc_dev.device (key, ip_address, type, name) VALUES (?, ?, ?, ?)]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, ip_address, type, name) VALUES ('abcd', 'abcd', 1234, 'abcd')' at line 1
root cause
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [INSERT INTO ibstechc_dev.device (key, ip_address, type, name) VALUES (?, ?, ?, ?)]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, ip_address, type, name) VALUES ('abcd', 'abcd', 1234, 'abcd')' at line 1
org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:237)
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72
My code segment is:
List<Device> devices = this.jdbcTemplate.query(
"select * from xyz.device a,xyz.user_device b "
+ "where b.user_id = ? and a.device_id = b.device_id and "
+ "a.type = ?",
new Object[]{userId,type},
new RowMapper<Device>() {
public Device mapRow(ResultSet rs, int rowNum) throws SQLException {
Device device = new Device();
device.setId(Long.valueOf(rs.getInt(1)));
device.setKey(rs.getString(2));
device.setIPAddress(rs.getString(3));
device.setType(rs.getInt(4));
device.setName(rs.getString(5));
return device;
}
});
System.out.println("Found for user..." + userId);
return devices;
}
public void create(Device device) {
this.jdbcTemplate.update("INSERT INTO xyz.device (key, ip_address, type, name) VALUES (?, ?, ?, ?)",
new Object[]{device.getKey(), device.getIPAddress(), device.getType(), device.getName()});
}
public void delete(Device device) {
this.jdbcTemplate.update("DELETE FROM xyz.device WHERE device_id = ?", new Object[] {device.getId()});
}
public void update(Device device) {
this.jdbcTemplate.update(
"UPDATE xyz.device SET key = ?, ip_address = ?, type = ?, name =? WHERE device_id = ?", new Object[]{device.getId(),device.getKey(), device.getIPAddress(), device.getType(), device.getName()});
And my Debug.java code is:
public String getNavBarData(){
Device device = new Device();
device.setKey("abcd");
device.setIPAddress("abcd");
device.setType(1234);
device.setName("abcd");
deviceDao.create(device);
return "";
The MySQL table has the same columns as in my code above with NOT NULL for each field. I have used the same code for a different functionality and it works there. Why am I getting this error for this one? Pls. Help.
KEY is a reserved word in Mysql. Therefore you either rename the column (which is better in a long run) or use back ticks around it.
That being said you insert statement should look like this
INSERT INTO xyz.device (`key`, ip_address, type, name) VALUES (?, ?, ?, ?)
^ ^
The same goes to your update statement
UPDATE xyz.device SET `key` = ?, ip_address = ?, type = ?, name =? WHERE device_id = ?
^ ^