Spring boot+Web mvc+JPA using CrudRepository giving issue on insert of a row using save method throwing EntityExistsException - spring-boot

Among CRUD operation Create is giving error of "A different object with the same identifier value was already associated with the session" Rest all (Read, Update and Delete) is working fine.
Im using oracle sql as database and there is one more entity of product with many to one mapping with categories class.
EntityClass
#Entity
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Categories() {
super();
}
public Categories(Integer id,String name) {
this.id=id;
this.name=name;
}
public Categories(String name) {
this.name=name;
}
//with setters and getters
}
JSP page
<body onload="document.getElementById('name').disabled = true;document.getElementById('hidden').disabled = true;">
<div align="center">
<h4>Add or Modify or Delete Categories</h4>
<form:form method="POST" action="/categories" modelAttribute="categories">
<table>
<tr>
<td><form:label path="name">Name</form:label></td>
<td>
<form:select path="name">
<form:option value="NONE" label="Select" />
<form:options items="${categoriesList}" />
</form:select>
</td>
</tr>
<tr>
<td>Operations</td>
<td>
<input type="radio" name="Ops" value="Add" checked="checked" onclick="document.getElementById('name').disabled = true; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Add</input><br/>
<input type="radio" name="Ops" value="Modify" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Modify</input><br/>
<input type="radio" name="Ops" value="Delete" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = true;document.getElementById('hidden').disabled = false;">Delete</input><br/>
</td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" name="newName" id="newName"/>
<input type="hidden" id="hidden" name="newName" value="dummy"/>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
</body>
Controller Class
#Controller
public class CategoriesController {
#Autowired
private CategoriesService cservice;
#RequestMapping(value = "/categories", method = RequestMethod.GET)
public ModelAndView categories() {
// view name model
ModelAndView modelAndView = new ModelAndView("categories", "categories", new Categories());
return modelAndView;
}
#RequestMapping(value = "/categories", method = RequestMethod.POST)
public String opsOnCategories(#ModelAttribute("categories") Categories cat,#RequestParam("Ops") String ops,#RequestParam("newName") String name)
{
if(ops.equals("Modify"))
{
cservice.modifyCategory(new Categories(Integer.parseInt(cat.getName()), name));
}else if(ops.equals("Add"))
{
cservice.addCategory(new Categories(name));
}else
{
cservice.deleteCategory(Integer.parseInt(cat.getName()));
}
return "categories";
}
#ModelAttribute("categoriesList")
public Map<String, String> getCategoryList() {
Map<String, String> categoriesList = new HashMap<String, String>();
List<Categories> ls=cservice.getAll();
for(int i=0;i<ls.size();i++)
{
categoriesList.put(ls.get(i).getId().toString(), ls.get(i).getName());
}
return categoriesList;
}
}
Can anyone please help on this.
Previous one due to which there was error
insert into CATEGORIES(ID,NAME) values (1,'Mobile');
insert into CATEGORIES(ID,NAME) values (2,'Laptop');
**Changes made to remove error*
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Mobile');
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Laptop');

My initial guess is that there something wrong with #Id #GeneratedValue with Oracle Database specifically.
There are couple of things that you can do:
1- Try to connect to any other Database type just to test the functionality - so that you can rule out what doesn't matter
2- Try to use the #org.springframework.data.annotation.Id alongside with the #Id of javax persistence
Something that look like this
#Id
#org.springframework.data.annotation.Id
private Integer id;
3- Create a class that Generates random Integer Ids and refer to it using the annotations (#GenericGenerator & #GeneratedValue)

Related

I am getting an error 500, while i am trying to show all the products that exist in my database using SpringBoot

when i create a product and fill out the details in the create_product.html page when i click on add button, it should direct me to the Products.html page which I will show all the products but I am getting an error when I transferred me to the Products.html page. However, when i check my database table I found that the product had been added.
ProductController Class
#Controller
public class ProductsController {
//adding the service layer of the product
#Autowired
private ProductService productService;
#Autowired
private CategoriesRepository categoriesRepository;
public ProductsController(ProductService productService,CategoriesRepository categoriesRepository )
{
super();
this.productService = productService;
this.categoriesRepository = categoriesRepository;
}
// models
#ModelAttribute("category")
public List<Categories> initializeCategories(){
List<Categories> categories = categoriesRepository.findAll();
return categories ;
}
#ModelAttribute("product")
public Products products()
{
return new Products();
}
/////////////////////////////////// handllers
//request to list all the products
#RequestMapping("/products/all_products")
public String listProducts(Model model)
{
model.addAttribute("product",productService.getAllProducts());
return "Products/products";
}
//request to show the form to create a product // when u are accessing the http request u will access that one coz it will show the form and then the Save method will do the action
#GetMapping("/products/new/product")
public String createProductForm(Model model)
{
//Create product object
Products product = new Products();
model.addAttribute("product",product); // product is the object from products Entityclass
return "Products/create_product";
}
//request to create/save a product
#RequestMapping(value = "/products/create_product",method = RequestMethod.POST)
public String saveProduct(#ModelAttribute("product") Products product) // Products is the name of the Entity class and creating a productObjcet from it
{
productService.saveProduct(product);
return "redirect:/products/all_products";
}
#GetMapping("/products/edit/{id}")
public String editProductForm(#PathVariable long id, Model model)
{
model.addAttribute("product",productService.getProductById(id));
return "Products/edit_product";
}
//request to update product
#RequestMapping(value = "/products/update_product/{id}",method=RequestMethod.POST)
public String updateProduct(#PathVariable Long id, #ModelAttribute("product") Products product, Model model) // model Attribute is the data taken from the html file by the user
{
//get product from the db by id
Products existingProduct = productService.getProductById(id);
existingProduct.setProduct_id(id);
existingProduct.setProduct_name(product.getProduct_name());
existingProduct.setProduct_price(product.getProduct_price());
existingProduct.setProduct_category(product.getProduct_category());
existingProduct.setProduct_quantity(product.getProduct_quantity());
existingProduct.setProduct_Section(product.getProduct_Section());
existingProduct.setProduct_ExpDate(product.getProduct_ExpDate());
//updating the product
productService.updateProduct(existingProduct);
return "redirect:/products/all_products";
}
//request to Delete product
#GetMapping("/products/delete_product/{id}")
public String deleteProduct(#PathVariable long id)
{
productService.deleteProduct(id);
return "redirect:/products/all_products";
}
}
Categories Entity Class:
#Entity
#Data
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long categories_id;
private String categoryName;
#OneToMany(mappedBy = "product_category",fetch = FetchType.LAZY) //the name of the variable in the other class
private Set<Products> product_category = new HashSet<>();
public Categories(String categoryName, Set<Products> product_category) {
this.categoryName = categoryName;
this.product_category = product_category;
}
public Categories() {
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
Product Entity class :
#Entity
#Table(name = "Products")
#Data
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long product_id;
private String product_name;
private BigDecimal product_price;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categories_id") //the name of the column in the other class and that name will be a column in the class
private Categories product_category;
private String product_quantity;
private String product_Section;
private String product_ExpDate;
public Products()
{
super();
}
public Products(String product_name, BigDecimal product_price,String product_quantity,Categories product_category ,String product_Section,String product_ExpDate) {
this.product_name = product_name;
this.product_category = product_category;
this.product_price = product_price;
this.product_quantity = product_quantity;
this.product_Section = product_Section;
this.product_ExpDate = product_ExpDate;
}
ProductService Class:
#Service
public class ProductServiceImp implements ProductService {
//productRepository class
private ProductRepository productRepository;
public ProductServiceImp(ProductRepository productRepository) {
this.productRepository = productRepository;
}
#Override
public List<Products> getAllProducts() {
return this.productRepository.findAll();
}
#Override
public Products saveProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public Products updateProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public void deleteProduct(long id) {
this.productRepository.deleteById(id);
}
public Products getProductById(long id)
{
return productRepository.findById(id).get();
}
}
CreateProduct.html page:
<form th:action="#{/products/create_product}" method="post" th:object="${product}">
<div class="form-group">
<label class="control-label" for="product_name"> Product Name </label> <input
id="product_name" class="form-control" th:field="*{product_name}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_price"> Price </label> <input
id="product_price" class="form-control" th:field="*{product_price}" required
autofocus="autofocus" />
</div>
<div class="col-1.5">
<label th:for="category"> Category </label>
<select class="form-control form-control-sm" id="category" name="product_category">
<option value=""> Select Category </option>
<option th:each = "category: ${category}"
th:value="${category.categories_id}"
th:text="${category.categoryName}"
> <!--th:field="*{product_category}"-->
</option>
</select>
</div>
<br>
<div class="form-group">
<label class="control-label" for="product_quantity"> Quantity </label> <input
id="product_quantity" class="form-control" type="text"
th:field="*{product_quantity}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_Section"> Section </label> <input
id="product_Section" class="form-control" type="text"
th:field="*{product_Section}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_ExpDate"> Expire Date </label> <input
id="product_ExpDate" class="form-control" type="text"
th:field="*{product_ExpDate}" required autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
products.html page
<table class = "table table-striped table-bordered">
<thead class = "table-dark">
<tr>
<th> Category </th>
<th> Product Name </th>
<th> Product Price </th>
<th> Product Quantity </th>
<th> Product Section </th>
<th> Product Expiry Date </th>
<th> Edit </th>
<th> Delete </th>
</tr>
</thead>
<tbody>
<tr th:each = "product: ${product}"> <!-- this attribute to list up products -->
<td th:text="${product.product_category}" ></td>
<td th:text="${product.product_name}"></td>
<td th:text="${product.product_price}"></td>
<td th:text="${product.product_quantity}" ></td>
<td th:text="${product.product_Section}" ></td>
<td th:text="${product.product_ExpDate}" ></td>
<td> <center> <a th:href="#{/products/edit/{id}(id=${product.product_id})}" style="color: green"> Edit </a> </center> </td>
<td> <center> <a th:href="#{/products/delete_product/{id}(id=${product.product_id}) }" style="color: red"> Delete </a> </center> </td>
</tr>
</tbody>
</table>
FullTrace Error:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Oct 20 03:45:45 EDT 2021
There was an unexpected error (type=Internal Server Error, status=500).
No message available
java.lang.StackOverflowError
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:696)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:930)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:390)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:163)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458)
at com.example.warehouseManagementSystem.Entities.Categories.hashCode(Categories.java:10)
at com.example.warehouseManagementSystem.Entities.Products.hashCode(Products.java:10)
at java.base/java.util.HashMap.hash(HashMap.java:340)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.add(HashSet.java:221)
The problem is that you are using #Data from Lombok on your entity. Remove this and manually implement equals() and hashCode in a way that does not lead to a StackOverflowError. In most cases, you only want to check the primary key.
See https://www.wimdeblauwe.com/blog/2021/04/26/equals-and-hashcode-implementation-considerations/ for more info on how to correctly implement equals and hashcode.
See also https://thorben-janssen.com/lombok-hibernate-how-to-avoid-common-pitfalls/#Avoid_Data for more info on why you should be careful with Lombok and JPA/Hibernate.

How to make Search data using Spring boot

i am a beginner of spring boot framework.i want to work with search records using spring boot application. my index.html is loaded successfully when i enter the employee id on the employee id textbox and click search button relevant employee name result want to display the below textbox.but i don't know how to pass it .what i tired so so i attached below.
index.html
<form action="#" th:action="#{/search}" th:object="${employee}" method="post">
<div alight="left">
<tr>
<label class="form-label" >Employee ID</label>
<td>
<input type="hidden" th:field="*{id}" />
<input type="text" th:field="*{id}" class="form-control" placeholder="Employee ID" />
</td>
</tr>
</div>
<br>
<tr>
<td colspan="2"><button type="submit" class="btn btn-info">Search</button> </td>
</tr>
<div alight="left">
<tr>
<label class="form-label" >Employee Name</label>
<td>
<input type="text" th:field="*{ename}" class="form-control" placeholder="Employee Name" />
</td>
</tr>
</div>
</form>
Controller
#Controller
public class EmployeeController {
#Autowired
private EmployeeService service;
#GetMapping("/")
public String add(Model model) {
List<Employee> listemployee = service.listAll();
// model.addAttribute("listemployee", listemployee);
model.addAttribute("employee", new Employee());
return "index";
}
#RequestMapping("/search/{id}")
public ModelAndView showSearchEmployeePage(#PathVariable(name = "id") int id) {
ModelAndView mav = new ModelAndView("new");
Employee emp = service.get(id);
mav.addObject("employee", emp);
return mav;
}
}
Entity
#Entity
public class Employee {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String ename;
private int mobile;
private int salary;
public Employee() {
}
public Employee(Long id, String ename, int mobile, int salary) {
this.id = id;
this.ename = ename;
this.mobile = mobile;
this.salary = salary;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getMobile() {
return mobile;
}
public void setMobile(int mobile) {
this.mobile = mobile;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [id=" + id + ", ename=" + ename + ", mobile=" + mobile + ", salary=" + salary + "]";
}
Repository
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
It is easiest to create a dedicated form data object:
public class EmployeeSearchFormData {
private long employeeId;
// getter and setter
}
In the controller:
#Controller
public class EmployeeController {
#Autowired
private EmployeeService service;
#GetMapping("/")
public String add(Model model) {
model.addAttribute("employeeSearchFormData", new EmployeeSearchFormData());
return "index";
}
#PostMapping("/search")
public String doSearchEmployee(#ModelAttribute("employeeSearchFormData") EmployeeSearchFormData formData, Model model) {
Employee emp = service.get(formData.getEmployeeId());
model.addAttribute("employee", emp);
return "index";
}
}
Thymeleaf template:
<form action="#" th:action="#{/search}" th:object="${employeeSearchFormData}" method="post">
<div alight="left">
<tr>
<label class="form-label" >Employee ID</label>
<td>
<input type="text" th:field="*{employeeId}" class="form-control" placeholder="Employee ID" />
</td>
</tr>
</div>
<br>
<tr>
<td colspan="2"><button type="submit" class="btn btn-info">Search</button> </td>
</tr>
<div alight="left">
<tr>
<label class="form-label" >Employee Name</label>
<td>
<input type="text" th:field="${employee.ename}" class="form-control" placeholder="Employee Name" />
</td>
</tr>
</div>
</form>
Note the use of th:field="${employee.ename}" and not use *{...}. I also removed the hidden field as it does not seem needed to have it to me.
As an alternative, you can have the #PostMapping redirect to /employee/<id> if there is an endpoint available like that:
#PostMapping("/search")
public String doSearchEmployee(#ModelAttribute("employeeSearchFormData") EmployeeSearchFormData formData) {
return "redirect:/employee/" + formData.getEmployeeId();
}

Using logged in userid(foreign_key) for fillling out form in oneToMany mapping

I am working on spring-mvc application which uses Spring Security to login and hibernate as the ORM tool. So, my project only has 2 tables, Table Person has OneToMany mapping with Table Notes. So, once the user is logged into the system, he/she should be able to add notes, but while adding I would like to also save the Person's id, which is why I have used to OneToMany mapping. But I don't know how to get user's id and put it in the form. Below is my code.
The error is
org.postgresql.util.PSQLException: ERROR: null value in column "personid" violates not-null constraint
Which is understandable, thats why I want to know how I can retreive the personid.
Person model :
#Entity
#Table(name="person")
public class Person implements UserDetails{
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_USER");
#Id
#Column(name="personid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "person_seq_gen")
#SequenceGenerator(name = "person_seq_gen",sequenceName = "person_seq")
private int id;
#OneToMany(mappedBy = "person1")
private Set<Notes> notes1;
}
Note model :
#Entity
#Table(name="note")
public class Notes {
#Id
#Column(name="noteid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "note_gen")
#SequenceGenerator(name = "note_gen",sequenceName = "note_seq")
private int noteId;
#ManyToOne
#JoinColumn(name = "personid")
private Person person1;
}
SQL :
CREATE TABLE public.person (
personid INTEGER NOT NULL,
firstname VARCHAR,
username VARCHAR,
password VARCHAR,
CONSTRAINT id PRIMARY KEY (personid)
);
CREATE TABLE public.note (
noteid INTEGER NOT NULL,
sectionid INTEGER,
canvasid INTEGER,
text VARCHAR,
notecolor VARCHAR,
noteheadline VARCHAR,
personid INTEGER NOT NULL,
CONSTRAINT noteid PRIMARY KEY (noteid)
);
ALTER TABLE public.note ADD CONSTRAINT user_note_fk
FOREIGN KEY (personid)
REFERENCES public.person (personid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
Person controller :
#Controller
public class PersonController {
private PersonService personService;
#Autowired(required=true)
#Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String listPersons(Model model) {
model.addAttribute("person", new Person());
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
//For add and update person both
#RequestMapping(value= "/person/add", method = RequestMethod.POST)
public String addPerson(#ModelAttribute("person") Person p){
//new person, add it
this.personService.addPerson(p);
return "redirect:/";
}
NoteController :
#Controller
public class NoteController {
private NotesService notesService;
#Autowired(required=true)
#Qualifier(value="notesService")
public void setNotesService(NotesService notesService){this.notesService=notesService;}
#RequestMapping(value = "/notes", method = RequestMethod.GET)
public String listNotes(Model model) {
model.addAttribute("notes", new Notes());
model.addAttribute("listnotes", this.notesService.listNotes());
return "notes";
}
#RequestMapping(value= "/note/add", method = RequestMethod.GET)
public String addNote(#ModelAttribute("notes") Notes p){
this.notesService.addNote(p);
return "redirect:/";
}
}
Note.jsp (here is where I add notes.)
<c:url var="addAction" value="/note/add" ></c:url>
<form:form action="${addAction}" commandName="notes">
<table>
<c:if test="${!empty notes.note}">
<tr>
<td>
<form:label path="noteid">
<spring:message text="noteid"/>
</form:label>
</td>
<td>
<form:input path="noteid" readonly="true" size="8" disabled="true" />
<form:hidden path="noteid" />
</td>
</tr>
</c:if>
<tr>
<td>
<form:label path="note">
<spring:message text="note"/>
</form:label>
</td>
<td>
<form:input path="note" />
</td>
</tr>
<tr>
<td>
<form:label path="notetag">
<spring:message text="notetag"/>
</form:label>
</td>
<td>
<form:input path="notetag" />
</td>
</tr>
<tr>
<td>
<form:label path="notecolor">
<spring:message text="notecolor"/>
</form:label>
</td>
<td>
<form:input path="notecolor" />
</td>
</tr>
<tr>
<td>
<form:label path="canvasid">
<spring:message text="canvasid"/>
</form:label>
</td>
<td>
<form:input path="canvasid" />
</td>
</tr>
<tr>
<td>
<form:label path="sectionid">
<spring:message text="sectionid"/>
</form:label>
</td>
<td>
<form:input path="sectionid" />
</td>
</tr>
<tr>
<td colspan="2">
<c:if test="${!empty notes.note}">
<input type="submit"
value="<spring:message text="Edit note"/>" />
</c:if>
<c:if test="${empty notes.note}">
<input type="submit"
value="<spring:message text="Add note"/>" />
</c:if>
</td>
</tr>
</table>
</form:form>
Not sure if I understood you correctly but when there is a logged in user (Principal) in a thread then you can just use SecurityContextHolder.getContext().getAuthentication().getPrincipal() to get the Principal or just inject it using #AuthenticationPrincipal or just make sure your Person implements Principal interface and inject it directly (I assume a Person is a User and a User is a Principal) to get the person.id.
In /note/add try like this:
public String addNote(#ModelAttribute("notes") Notes p, #AuthenticationPrincipal Person person)) {
p.setPerson1(person);
this.notesService.addNote(p);
return "redirect:/";
}
If you want to avoid setting it manually consider usage of AuditorAware and Auditable like here:
http://www.springbyexample.org/examples/spring-data-jpa-auditing-code-example.html

Spring-Hibernate insertion Error with Column 'unit_id' cannot be null Exception

I am developing a small Spring and hibernate base application in java, and my appication has a one to many relationship with Employee and Unit, Employee has a one unit, Unit has a many Employee.
in this small application genarate error like this `
I was hard code data to Unit schema table, i populate unit combobox filled in jsp its works, but inside the #controller unit has a null data.
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Column 'unit_id' cannot be null
if allow to null value to unit_id other data inserted with out insert unit_id
here my Entity class
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "epf")
private int epf;
#Column(name = "fname")
private String fname;
#Column(name = "lname")
private String lname;
#Column(name = "email")
private String email;
#JoinColumn(name = "unit_id", referencedColumnName = "id")
#ManyToOne//(optional = false)
private Unit unit;
#Entity
#Table(name = "unit")
public class Unit implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
My controller Class
#Autowired
private EmployeeService employeeService;
private DesignationService designationService;
#RequestMapping({"/index", "/"})
public String setupForm(Map<String, Object> map){
Employee student = new Employee();
map.put("employee", student);
map.put("employeeList", employeeService.getAllEmployee());
map.put("unitList", employeeService.getAllUnitList());
return "employee";
}
#RequestMapping(value="/employee.do", method=RequestMethod.POST)
public ModelAndView doActions(#ModelAttribute Employee emp, BindingResult result, #RequestParam String action, Map<String, Object> map){
ModelAndView modelAndView = new ModelAndView("employee");
Employee employeetResult = new Employee();
switch(action.toLowerCase()){ //only in Java7 can put String in switch
case "add":
employeeService.addEmployee(emp);
employeetResult = emp;
break;
case "edit":
employeeService.updateEmployee(emp);
employeetResult = emp;
break;
case "delete":
employeeService.deleteEmployee(emp.getId());
employeetResult = new Employee();
break;
case "search":
Employee searchedStudent = employeeService.getEmployee(emp.getId());
employeetResult = searchedStudent!=null ? searchedStudent : new Employee();
break;
}
map.put("employee", employeetResult);
map.put("employeeList", employeeService.getAllEmployee());
return modelAndView;
}
My JSP
<form:form action="employee.do" method="POST" commandName="employee">
<table width="341" border="0">
<tr>
<td width="154"> </td>
<td width="21"> </td>
<td width="152"> </td>
</tr>
<tr>
<td><spring:message code="employee.id"/></td>
<td> </td>
<td><form:input path="epf" /></td>
</tr>
<tr>
<td><spring:message code="employee.epf"/></td>
<td> </td>
<td><form:input path="epf" /></td>
</tr>
<tr>
<td><spring:message code="employee.fname"/></td>
<td> </td>
<td><form:input path="fname"/></td>
</tr>
<tr>
<td><spring:message code="employee.lname"/></td>
<td> </td>
<td><form:input path="lname" /></td>
</tr>
<tr>
<td><spring:message code="employee.email"/></td>
<td> </td>
<td><form:input path="email" /></td>
</tr>
<tr>
<td><spring:message code="employee.unit"/></td>
<td> </td>
<!-- Unit Combo filling --><td>
<form:select path="unit" multiple="false" size="1">
<form:options items="${unitList}" itemValue="id" itemLabel="name"/>
</form:select>
<!-- Unit Combo filling end --></td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="action" value="Add" />
<input type="submit" name="action" value="Edit" />
<input type="submit" name="action" value="Delete" />
<input type="submit" name="action" value="Search" />
</td>
</tr>
</table>
</form:form>
My DAO Class
> #Repository public class EmployeeDaoImp implements EmployeeDao {
>
> #Autowired private SessionFactory sessionfactory;
> public void addEmployee(Employee emp) { sessionfactory.getCurrentSession().save(emp);
>
> }
>
> public void updateEmployee(Employee emp) {
> sessionfactory.getCurrentSession().update(emp);
>
> }
>
> public void deleteEmployee(int id) {
> sessionfactory.getCurrentSession().delete(getEmployee(id)); }
>
> Employee public Employee getEmployee(int empId) {
> return (Employee) sessionfactory.getCurrentSession().get(Employee.class,empId); }
>
> public List getAllEmployee() {
> return sessionfactory.getCurrentSession().createQuery("from Employee").list(); }
The id is primary key in the DB. You are save an object without giving it's value. So either make it auto increment in table or generate it's value using hibernate.

How to populate a form:select and select a default value?

I have an edit user form which has textfields(username, lastname..) and a select of countries. I'm having problems with this select because i don't know the better way to populate it. I've tried populating with jquery with success but i cannot select a default value through commandName.
<form:form method="POST" commandName="user" action="registerUser.html">
<form:errors path="*" cssClass="errorblock" element="div" />
<spring:message code="app.user.username"/><form:input path="username" /><form:errors path="username" cssClass="error" /><br/>
<spring:message code="app.user.firstname"/> <form:input type="text" path="firstName" /> <form:errors path="firstName" cssClass="error"/><br/>
<spring:message code="app.user.password"/> <form:input type="password" path="password" /><form:errors path="password" cssClass="error"/><br/>
<spring:message code="app.user.repassword"/> <form:input type="password" path="confirmPassword" /><form:errors path="confirmPassword" cssClass="error"/><br/>
<spring:message code="app.user.email"/> <form:input type="text" path="email" /><form:errors path="email" cssClass="error"/><br/>
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
<input type="submit" value="Enviar" />
</form:form>
I've take a look to this tutorial, so i've tried with a map but i don't know how to return the data to be accesible in the jsp because in the tutorial uses a SimpleFormController but i wouldn't like to code a SimpleFormController for each form. This is my controller to return the view of the form and i have another to catch the submit.
#RequestMapping(method=RequestMethod.GET, value="/editUserForm")
public String recordUserRequestHandler(ModelMap model) throws Exception {
model.addAttribute("user", new User());
Map<String, Map<String, String>> referenceData = new HashMap<String, Map<String, String>>();
Map<String, String> country = new LinkedHashMap<String, String>();
country.put("US", "United Stated");
country.put("CHINA", "China");
country.put("SG", "Singapore");
country.put("MY", "Malaysia");
referenceData.put("countryList", country);
return "EditUserForm";
}
is it possible to pass the referenceData to the jsp to be accessed by the form:select?
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
Also you don't need to use hashmap for selects. Personally I use simple List with beans which holds my select options.
public class ListOption {
private String id;
private String name;
public ListOption(String id, String name) {
this.id = id;
this.name = name;
}
public ListOption() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
in your controller
List<ListOption> selectOptions = new List<ListOption>();
// add Your options
selectOptions.add(new ListOption("id","value");
then put isoCode object into your model with desired (selected) value then spring will manage to mark the value as selected.
in your jsp
<form:select path="isoCode" items="${countryList}" itemValue="id" itemLabel="name"/>

Resources