When update Employee table then why new row inserted in Address table. I want simple update Address table also - spring

Note: When update Employee why new row inserted in Address table. I want to update Employee and want to update Address table also rather than new row inserted.
After execute following:
session=sessionFactory.getCurrentSession();
session.update(employee);
Result:
Hibernate: insert into Address (address, employee_empId, mobile, pincode) values (?, ?, ?, ?)
Hibernate: update Employee set addId=?, empName=?, empProfile=? where empId=?
#Entity
#Table(name = "Address")
public class Address {
#Id
#Column(name = "addId", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int addId;
#Column(name = "pincode", unique = false, nullable = false, length = 100)
int pincode;
#Column(name = "address", unique = false, nullable = false, length = 100)
String address;
#Column(name = "mobile", unique = false, nullable = false, length = 100)
String mobile;
#OneToOne
private Employee employee;
public int getAddId() {
return addId;
}
public void setAddId(int addId) {
this.addId = addId;
}
public int getPincode() {
return pincode;
}
public void setPincode(int pincode) {
this.pincode = pincode;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
#Entity
#Table(name = "Employee")
public class Employee {
#Id
#Column(name = "empId", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
int empId;
#Column(name = "empName", unique = false, nullable = false, length = 100)
String empName;
#Column(name = "empProfile", unique = false, nullable = false, length = 100)
String empProfile;
#OneToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name="addId")
Address address;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpProfile() {
return empProfile;
}
public void setEmpProfile(String empProfile) {
this.empProfile = empProfile;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
<form:form cssClass="form-horizontal" method="POST" action="${pageContext.request.contextPath}/editEmployee" modelAttribute="employee">
<input type="hidden" value="${employeeDetail.empId}" name="empId">
<div class="form-group">
<label for="email">Employee Name:</label>
<input type="text" class="form-control" name="empName" value="${employeeDetail.empName}">
</div>
<div class="form-group">
<label for="pwd">Profile:</label>
<textarea rows="5" class="form-control" name="empProfile">${employeeDetail.empProfile}</textarea>
</div>
<div class="form-group">
<label for="pwd">Pincode:</label>
<input type="text" class="form-control" name="address.pincode" value="${employeeDetail.address.pincode}">
</div>
<div class="form-group">
<label for="pwd">Address:</label>
<textarea rows="5" class="form-control" name="address.address">${employeeDetail.address.address}</textarea>
</div>
<div class="form-group">
<label for="pwd">Mobile No:</label>
<input type="text" class="form-control" name="address.mobile" value="${employeeDetail.address.mobile}">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form:form>
After execute following:
session=sessionFactory.getCurrentSession();
session.update(employee);
Result:
Hibernate: insert into Address (address, employee_empId, mobile, pincode) values (?, ?, ?, ?)
Hibernate: update Employee set addId=?, empName=?, empProfile=? where empId=?
Note: When update Employee why new row inserted in Address table. I want to update Employee and want to update Address table also rather than new row inserted.

Related

Thymeleaf access object in outerloop from innerloop

i am looping through a list of "roles" , inside each one i loop through a list of "notifications" ( a role can have many notifications )
<div class="row justify-content-center">
<div class="col-sm-3" th:each="role : ${roles}">
<div class="card">
<div class="card-body">
<h5 class="card-title" th:text="${role.name}"></h5>
Notifications :
<div class="input-group mb-3">
<th:block th:each="notif : ${notif_list}">
<div class="custom-control custom-control-inline">
<input type="checkbox" class="custom-control-input"
th:id="${notif.id_notif_type}"
th:value="${notif.id_notif_type}" th:field="${role.notifs}">
<label class="custom-control-label" th:text="${notif.type}"
th:for="${notif.id_notif_type}"></label>
</div>
</th:block>
</div>
</div>
</div>
</div>
</div>
i want access an object "role" inside the notification loop by using th:field="${role.notifs}
here is my Role class :
#Entity
#Table(name = "roles")
#Transactional
public class Role implements Serializable{
public Role() {
}
public Role(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinTable(name = "roles_notifs", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "notif_id"))
private Set<NotifType> notifs = new HashSet<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<NotifType> getNotifs() {
return notifs;
}
public void setNotifs(Set<NotifType> notifs) {
this.notifs = notifs;
}
public void addNotif(NotifType notif) {
notifs.add(notif);
}
public void removeNotif(NotifType notif) {
notifs.remove(notif);
}
#Override
public String toString() {
return name;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
i got an error on ${role.notifs} , so how can i access the outer object "role" from the inner loop.
i got this error Neither BindingResult nor plain target object for bean name 'role' available as request attribute

How to save the image file associated with user in springboot, thymeleaf

I am trying to save the image file and the item details to mysql database, However i got an
error.
I am using thymeleaf for the front end.
Here is my item upload form:
#GetMapping("/itemUploadForm")
public String itemUploadForm(Model theModel) {
Item theItem = new Item();
theModel.addAttribute("item", theItem);
return "fileUploadForm";
}
This part is to process the image and the item details once taken from the user.
#PostMapping("/itemUploadProcess")
public String itemUploadProcess(#ModelAttribute("item") Item theItem,#RequestParam("imagefile") MultipartFile imageFile) throws Exception {
String folder = "/photos";
byte[] bytes = imageFile.getBytes();
Path path = Paths.get(folder + imageFile.getOriginalFilename());
Files.write(path, bytes);
itemService.save(theItem);
return "redirect:/";
}
This is a class item.
I dont know if the problem is in this properties or in mysql.
I have mysql column for file set as imagefile blob not null;
package com.rentyou.projectdemo.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.springframework.web.multipart.MultipartFile;
#Entity
#Table(name = "item")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int id;
#Column(name = "name")
public String name;
#Column(name = "description")
public String description;
#Column(name = "conditiontype")
public String type;
#Column(name = "price")
public String price;
#Column(name = "contact")
public String contact;
#Column(name = "itemimage")
public MultipartFile itemImage;
public Item() {
}
public Item(String name, String description, String type, String price, String contact, MultipartFile itemImage) {
this.name = name;
this.description = description;
this.type = type;
this.price = price;
this.contact = contact;
this.itemImage = itemImage;
}
public Item(int id, String name, String description, String type, String price, String contact,
MultipartFile itemImage) {
this.id = id;
this.name = name;
this.description = description;
this.type = type;
this.price = price;
this.contact = contact;
this.itemImage = itemImage;
}
public MultipartFile getItemImage() {
return itemImage;
}
public void setItemImage(MultipartFile itemImage) {
this.itemImage = itemImage;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
}
This part is the form to take image file and the item details:
<form th:action="#{/itemUploadProcess}"
th:object="${item}" method="POST" enctype="multipart/form-data">
<input type="text" th:field="*{name}"
class="form-control mb-4 col-4" placeholder="Name">
<input type="text" th:field="*{description}"
class="form-control mb-4 col-4" placeholder="Description">
<input type="text" th:field="*{type}"
class="form-control mb-4 col-4" placeholder="Condition">
<input type="text" th:field="*{price}"
class="form-control mb-4 col-4" placeholder="Price">
<input type="text" th:field="*{contact}"
class="form-control mb-4 col-4" placeholder="Contact">
<input type="file" th:field="*{itemImage}" class="form-control mb-4 col-4" placeholder="Contact" name="imagefile">
<button type="submit" class="btn btns-info col-2">Save</button>
</form>
Remove that attribute name="imagefile" from your form. Its giving the file the wrong name. The th:field attribute will supply the correct name attribute.

Thymeleaf Spring Validation doesn't display

I am trying display error message on HTML which i got from Controller, but i dont see the message displaying.
I printed the ${#fields.hasErrors('name')} and i see it give me false
I debugged my code, and I found there is an error
com.gurnah.controller.ProductController : product size must be between 2 and 150
#RequestMapping(path = "/product")
public class ProductController {
private static final Logger logger = LoggerFactory.getLogger(ProductController.class);
#Autowired
private ProductRepo productRepo;
.....
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(#ModelAttribute #Valid Product product, Errors errors, Model model) {
if (errors.hasErrors()) {
model.addAttribute("product", new Product());
// logger.info("Error Message " + bindingResult.getGlobalErrorCount());
logger.info("Error Message " + errors.getFieldErrorCount());
List<ObjectError> err = errors.getAllErrors();
for (ObjectError e : err) {
logger.info(e.getObjectName() + e.getDefaultMessage());
}
// logger.info("Error Message " + bindingResult.getErrorCount());
return "/prod/create";
} else {
productRepo.save(product);
return "redirect:/product/list";
}
}
My Pojo
#Entity
public class Product {
#Id
#Column(name = "ProdID", updatable = false, nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_generator")
#SequenceGenerator(name="product_generator", sequenceName = "zseq_product", allocationSize=1)
private int ProdID;
#NotNull(message = "Field Product cannot be empty")
// #NotEmpty(message = "Field Product cannot be empty")
#Size(min = 2, max = 150)
private String name;
private String prodDesc;
My HTML
<form th:object="${product}" th:action="#{/product/save}" method="post">
.....
<div class="form-group"
th:classappend="${#fields.hasErrors('name')}? 'has-error'">
<label th:for="name" class="col-form-label">Product Name:</label>
<input type="text" class="form-control" th:field="*{name}" />
<span th:if="${#fields.hasErrors('name')}"
th:errors="*{name}"
th:class="help-block">Title Errors</span>
</div>

Thymeleaf #sets.contains() always returning false despite usage according to documentation

Preface
I have a spring boot application with a User entity with a set of Role.
On the edit user template, I am displaying the user's roles with a <select>multiple. When rending the view of a existing User with its set of Role, I am trying to only mark as selected the roles within the set.
Thymeleaf provides two tools for this:
th:selected: Which expects a boolean value (true being selected)
#sets: Which provides a handful of useful methods similar to java.util.Set, the one being used in this case is contains().
The problem
When adding to the model a found User and all the possibles Role in the form of a HashSet, using #sets.contains() always return false when using the found user's roles and all the roles as parameters, therefore not selecting the user's roles when loading the form.
If I use the notation th:selected="${{user.roles}}" notation all the options are selected (even those the user does not posses).
The Code
User
public class User
{
private Long id;
private String username;
private String password;
private String passwordConfirm;
private Set<Role> roles;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
#Transient
public String getPasswordConfirm()
{
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm)
{
this.passwordConfirm = passwordConfirm;
}
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_role", joinColumns = #JoinColumn(name = "users_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
public Set<Role> getRoles()
{
return roles;
}
public void setRoles(Set<Role> roles)
{
this.roles = roles;
}
}
Role
public class Role
{
private Long id;
private String name;
private Set<User> users;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
#ManyToMany(mappedBy = "roles")
public Set<User> getUsers()
{
return users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
Controller
#Controller
#RequestMapping("/admin")
public class AdminController
{
#Autowired
UserService userService;
#Autowired
RoleService roleService;
#RequestMapping("/user/edit/{id}")
public String editUser(Model model, #PathVariable("id") long id)
{
User user = userService.findByUserId(id);
HashSet<Role> foundRoles = roleService.getAllRoles();
model.addAttribute("user", user);
model.addAttribute("userRoles", foundRoles);
return "admin/adminUserDetail";
}
}
The form
<form role="form" th:action="#{/registration}" method="POST"
th:object="${user}">
<div th:if="${#fields.hasErrors('*')}">
<div class="alert alert-danger" role="alert">
<h3 class="alert-heading">It seems we have a couple problems with your input</h3>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
</div>
</div>
<div class="form-group">
<label>Username: </label> <input class="form-control" type="text" th:field="${user.username}"
placeholder="Username" name="username"/>
<label>Password: </label> <input class="form-control" type="password" th:field="${user.password}"
placeholder="Password" name="password"/>
<label>Password Confirm: </label> <input type="password"
th:field="${user.passwordConfirm}" class="form-control"
placeholder="Password Confirm"/>
<select class="form-control" multiple="multiple">
<option th:each="role : ${userRoles}"
th:value="${role.id}"
th:selected="${#sets.contains(user.roles, role)}"
th:text="${role.name}">Role name
</option>
</select>
<button type="submit" class="btn btn-success">Update</button>
</div>
</form>
When using a Set the object in there must implement both hashCode and equals as that is used to determine if an object is already in the Set. Unless it is a SortedSet which uses either a Comparator or the natural order expressed through your object implementing Comparable.
As you don't do either of those using contains will simply always return false even for a seemingly same Role instance. Because according to the contract they aren't.
To fix implement the equals and hashCode method in your User and Role object.
public class Role {
public int hashCode() {
return Objects.hash(this.name);
}
public boolean equals(Object o) {
if (o == this) { return true; }
if (o == null || !(o instanceof Role) ) { return false; }
return Objects.equals(this.name, ((Role) o).name);
}
}
Something along those lines should do the trick.

Spring MVC + Hibernate Cannot get item property

I,m stuck. I have a problem with output of data. I try to make some kind of order-product project. My Entities are following:
#Entity
#Table(name = "sales")
public class Sale implements Serializable {
public Sale() {
}
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(insertable = false, updatable = false)
private Timestamp date;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "sale")
private List<OrderItem> items = new ArrayList<OrderItem>();
#Column
private double cost;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Timestamp getDate() {
return date;
}
public void setDate(Timestamp date) {
this.date = date;
}
public List<OrderItem> getItems() {
return items;
}
public void setItems(List<OrderItem> items) {
this.items = items;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
for(OrderItem item : items)
cost += item.getProduct().getPrice() * item.getQuantity();
this.cost = cost;
}
}
#Entity
#Table(name = "products")
public class Product implements Serializable {
public Product() {
}
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String name;
#Column
private double price;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "product")
private Set<OrderItem> items = new HashSet<OrderItem>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Set<OrderItem> getItems() {
return items;
}
public void setItems(Set<OrderItem> items) {
this.items = items;
}
public boolean isNew() {
return this.id == 0;
}
}
#Entity
#Table(name = "order_items")
public class OrderItem implements Serializable {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
#Column
private int quantity;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private Product product;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "sale_id")
private Sale sale;
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
SQL tables create like this:
CREATE TABLE products (
id SERIAL PRIMARY KEY NOT NULL,
name CHARACTER(50) NOT NULL,
price REAL NOT NULL
)
WITH ( OIDS = FALSE );
CREATE TABLE sales (
id SERIAL PRIMARY KEY NOT NULL,
cost REAL NOT NULL,
date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)
WITH ( OIDS = FALSE );
CREATE TABLE order_items (
id SERIAL NOT NULL,
sale_id INTEGER NOT NULL,
product_id INTEGER,
quantity INTEGER NOT NULL,
primary key (sale_id, id)
)
WITH ( OIDS = FALSE );
ALTER TABLE order_items
ADD CONSTRAINT order_itemsFK0 FOREIGN KEY (product_id) REFERENCES products(id);
ALTER TABLE order_items
ADD CONSTRAINT order_itemsFK1 FOREIGN KEY (sale_id) REFERENCES sales(id);
My sale form:
<form:hidden path="id" />
<spring:bind path="items">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Product</label>
<div class="col-sm-5">
<form:select path="items" class="form-control">
<form:options items="${productMap}" />
</form:select>
<form:errors path="items" class="control-label" />
</div>
<div class="col-sm-5"></div>
</div>
</spring:bind>
<spring:bind path="items">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Quantity</label>
<div class="col-sm-10">
<form:radiobuttons path="items" items="${numberList}" element="label class='radio-inline'" />
<br />
<form:errors path="items" class="control-label" />
</div>
</div>
</spring:bind>
<spring:bind path="cost">
<div class="form-group ${status.error ? 'has-error' : ''}">
<label class="col-sm-2 control-label">Cost</label>
<div class="col-sm-10">
<form:input path="cost" type="text" class="form-control" id="cost"
placeholder="Cost" />
<form:errors path="cost" class="control-label" />
</div>
</div>
</spring:bind>
And i have problems on form where I try to add sale. Items is incorrect, doesn`t save. i write jsp code wrong but i have no idea how to get it right. Need help, please!
Do you have some log? make sure that your post is arriving to the server side.
Solved. I remade some stuff in the project, in jsp part. Add additive page and everything works good.

Resources