My Java Spring Boot application adds the suffix '_seq' to table users - mysql

On execution of my spring boot application with MySQL as data source, it fails with below error message
Table 'schema.users_seq' doesn't exist
I have an #Entity class Users with an AUTO_INC field Id
#Entity
#Table(appliesTo = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="uid")
private long id;
}
Below is my User controller class
#RestController
#RequestMapping("/cm/api/user")
public class UserController {
#Autowired
UsersRepository usersRepository;
#GetMapping("/{username}")
public void getUser(#PathVariable("username") String userName) {
}
#PostMapping("/add")
public void addNewUser(#RequestBody Users users) {
usersRepository.save(users);
}
}
There are some other articles on the same issue, but it all ended with the question if the class has AUTO_INC field.

Your app tries to generate a long ID for your Users entity by retrieving a value from the users_seq. You need to change the #GeneratedValue(strategy = GenerationType.AUTO) according to your DDL structure. As you didn't include that in your post, I can only assume how you mapped it, so I can only recommend that you read this article by Hibernate maintainer Vlad Mihalcea about why you should not use the AUTO JPA GenerationType with MySQL and Hibernate.

Related

Mapping EXCEL Sheet to Database using JPA Hibernate

I would like to map an simple excel table to my javaEE application using hibernate. I'm really new to Databases and ORM so i would like to know if the following relations make sense and in how many Entities would make sense to split the Table.
This is the attributes contained in the Excel spreadsheet:
(Office Room Number|ComputerName|ComputerIP|Computer OS|UserFirstName|UserLastName)
Relations:
OfficeRoomNumber -- 1 : N -- Users
N users working in 1 Office?
OfficeRoomNumber -- 1 : N -- Computer
N Computers are in 1 Office ?
User -- 1:1 -- Computer
1 User got 1 Computer?
Thanks for any help and sorry for my horrible English.
Here are my 50c for modelling your domain. First, one can use an abstract base class for generic aspects, such as primary key generation:
#MappedSuperClass
public abstract class AbstractEntity {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pk-sequence")
#SequenceGenerator(name = "pk-sequence", sequenceName = "ID_GEN", allocationSize = 1)
protected Long objectID = -1;
#Version
private int version;
public int getVersion() {
return version;
}
public long getObjectID() {
return objectID;
}
}
Note well, this can be enhanced to include other generic aspects, e.g. creation/modification date/timestamps.
Next, we introduce three domain classes/entities as follows:
#Entity
public class OfficeRoom extends AbstractEntity {
private String name;
private String roomNumer;
#ManyToMany // Maybe an employee is associated with 2 or more office places she/he might work at?
private Collection<Employee> staff;
#OneToMany(mappedBy="location")
private Collection<Computer> equipment;
// getters and setters
}
I added a comment as you can see above on the field staff. Potentially, one would like to associated two different office rooms to certain VIP staff, so you should consider this case in modelling your domain by using #ManyToMany here already.
Moving on with:
#Entity
public class Computer extends AbstractEntity {
private String name;
private String model;
private String vendor;
private String installedOS;
private String ipAddress;
#ManyToOne
private OfficeRoom location;
#OneToMany(mappedBy="machine") // Maybe a computer is associated with 2 or more employees?
private Collection<Employee> user;
// getters and setters
}
Again, consider my comment carefully. Finally,...
#Entity
public class Employee extends AbstractEntity {
private String firstName;
private String lastName;
// other staff related attributes here ...
#ManyToOne
private Computer machine;
// getters and setters
}
Note well: Use only annotations originating from the javax.persistence package, in your import statements to stay compliant with the JPA 2.x specification and remain JPA-provider neutral with your application.
Hope this helps.

(Hibernate, mysql) Caused by: java.sql.SQLException: Field 'id' doesn't have a default value

I have an application which was running on H2 database and Hibernate is the ORM tool. Currently, I am changing this application to use mysql database instead of H2 database and while doing this I came to this issue when saving flagjp entity.
Here is the FlagJP entity that caused this issue.
#Entity
public class FlagJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagId;
private String flagKey;
#OneToMany(mappedBy="flag", cascade = CascadeType.ALL)
private List<FlagLangJP> flagLangs = new ArrayList<>();
#ManyToOne
private FlagCategoryJP flagCategory;
Here are the related entities for the FlagJP
Second entity
#Entity
public class FlagLangJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long id;
private String languageCode;
private String flagName;
private String flagDescription;
#ManyToOne
private FlagJP flag;
Third Entity
#Entity
public class FlagCategoryJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagCategoryId;
private String flagCategoryName;
#OneToMany(mappedBy = "flagCategory")
private List<FlagJP> flags;
While looking into this issue, I was able to figure out that this is cased by FlagJP table schema not having auto increment set in the database when hibernate generated the DDL.
here is the DDL of FlagJP
If I try to manually set the auto increment by executing a sql query, then mysql throw this error.
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1833: Cannot change column 'flagId': used in a foreign key constraint 'FK_sk95esyf1n0gt1qqmlmdmq0uw' of table 'butterfly_emenu.flaglangbpa'
SQL Statement:
my question is , this problem does not happen when using H2 database. how to solve this issue using hibernate when the database is mysql.
Thanks in advance for any advice
Update:
Here is the code for sequence generator I am using
public class JPSequenceGenerator extends IdentityGenerator {
private static final Logger logger = LoggerFactory.getLogger(JPSequenceGenerator.class);
#Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
if (id == null) {
id = super.generate(session, object);
}
return id;
}
}
Try below code with auto_increment field ID in mysql
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long flagId;
If you are not able to add auto_increment for flagId then remove the foreignKey FK_sk95esyf1n0gt1qqmlmdmq0uw then add auto_increment and add foreign key again

Persisting entity fetched from Jackson Json in Hibernate

Below is my scenario.
I have two entities.
1) Client
2) Project
Relationship among them is One client provides Many Projects. I have created both the entities in Hibernate as follows,
#Entity
#Table(name="client")
public class Client extends BaseEntity<Long> {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long clientId;
......
......
}
#Entity
#Table(name="Project")
public class Project extends BaseEntity<Long>{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long projectId;
.......
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "clientId")
private Client client;
.......
}
My Service Layer looks like,
#RestController
#RequestMapping("/project")
public class ProjectController {
#Autowired
private ProjectService projectService;
#RequestMapping(value = "/add", method = RequestMethod.POST)
public ResponseEntity<String> add(#RequestBody Project project, BindingResult result) throws JsonProcessingException {
........
projectService.saveProject(project);
....
}
}
My JSON while requesting the server is,
{
"name": "Project 1",
"description": "client Project 1",
"startDate": "2012-07-21 12:11:12",
"endDate": "2017-07-21 12:11:12",
"totalPlannedReleases": 20,
"projectKey": "MAQ",
"avatar":"Not Available",
"client": {"clientId":1}
}
My client (Parent entity) is already persisted in database. I have to reference the existing clientId to the new Project which I am inserting.
I am using Jackson as Json library
Is there any way so that Client entity can be mapped/fetched automatically while inserting Project?
What does 'automatically' mean?
If Project is the owning side of the client - project relationship (which it probably should be as per your requirement), you can call project.setClient(entityManager.getReference(Client.class, id)) (or project.setClient(session.load(Client.class, id)) if you are using Hibernate session) to avoid loading the entire state of the Client entity from the database.

With Spring Boot, how to post JSON object that represents an entity whose member is another entity

(***Edited*:**I am looking for the JSON representation of the solution provided here: Spring REST multiple #RequestBody parameters, possible?)
I have the following entity Account which has a member variable of another entity called Customer
#Entity
public class Account {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id=0;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
...
}
#Entity
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id=0;
private String customerId;
public Customer(){}
public Customer(String customerId){
this.customerId = customerId;
}
public long getId(){
return id;
}
public String getCustomerId(){
return customerId;
}
public void setCustomerId(String customerId){
this.customerId = customerId;
}
}
I need to post a JSON object representation of an Account. Here is the Controller method:
#Autowired
private AccountRepository accounts;
#RequestMapping(value="/accounts/account",method=RequestMethod.POST)
public #ResponseBody Account addAccount(#RequestBody Account account){
return accounts.save(account);
}
AccountRepository is an interface that extends CrudRepository
I have an existing customer with the URI http://localhost:8084/customers/customer/1
I have attempted to post the following JSON objects and received a 400 Bad Request response.
{"customer":"1"}
{"customer":"http://localhost:8084/customers/customer/1"}
{"customer":{"href":"http://localhost:8084/customers/customer/1"}}
Just to make sure that an Account can be created if correct data is received, I modified the controller method as per the following code, which created the account when I post to http://localhost:8084/accounts/account
#RequestMapping(value="/accounts/account",method=RequestMethod.POST)
public #ResponseBody Account addAccount() throws Exception{
Customer customer = customers.findOne(1);
Account account = new Account();
account.setCustomer(customer);
return accounts.save(account);
}
So my question is, how do I format a JSON object so as to Create an Entity whose member is an existing Entity?
I found out that the correct format is to provide the URI of the referenced entity, i.e in this case it should be
{"customer":"http://localhost:8084/customers/customer/1"}
However, this only worked after I added the data-rest dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>{spri}</version>
</dependency>
Without this dependency, the request fails with a JsonMappingException

ID auto generation for MySQL on JBoss AS 7

I need help to resolve such problem. Application needs to support several DB (MySQL, Oracle). After migration to JBoss 7 entity id auto generation was broken.
Etity example:
#Entity
#Table(name="foo")
public class Foo {
private Integer id;
private String model;
#Id
#SequenceGenerator(name="foo_seq_gen", sequenceName="foo_0", initialValue=1, allocationSize=1)
#Column(name="id", updatable=false)
#GeneratedValue(generator = "foo_seq_gen")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name="model", length=64, updatable=false)
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
For Oracle it works fine. But when trying to perform create operation on MySQL following error occures:
15:34:56,290 ERROR [org.hibernate.util.JDBCExceptionReporter] (http-localhost-127.0.0.1-8080-1) Table 'scheme.foo_0' doesn't exist
Thus MySQL tries to access non-existent table as sequence instead of using native autogeneration mechanism.
Does anybody know the cure?
Using "table" generator strategy didn't help.
Environment:
MySQL 5.5.16;
JBoss AS 7.1.0.Beta1;
Hibernate 3.6.1.
Thanks.
I' not sure if you need the #SequenceGenerator for Oracle, but with JBoss AS 7.1.0.CR1b and MySQL I have no problems with ID auto generation and this annotations:
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private long id;