Spring select multiple tag and binding - spring

I am trying to use the select tag of spring to select multiple options to fill a List.
My select tags is well displayed and when I select options the List is correctly updated.
The only problem I have is when I render the for with an already filled List, my select tag does not highlight the selected options. I have try to debug and Ican see that the List is not empty, it is really the tag that seems to not mark the selected options as selected.
My code :
#Entity
public class ProductsGroup
{
#Version #Column(name = "version")
private Integer version;
#Id #GeneratedValue(strategy = GenerationType.AUTO) #Column(name = "id")
private Integer id;
#ManyToMany(fetch = FetchType.EAGER)
private List<Product> products;
public List<Product> getProducts()
{
return products;
}
public void setProducts(List<Product> products)
{
this.products = products;
}
}
#Entity
public class Product
{
#Version #Column(name = "version")
private Integer version;
#Id #GeneratedValue(strategy = GenerationType.AUTO) #Column(name = "id")
private Long id;
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
<form:form action="${action}" class="fancyform" commandName="productsGroup" id="productForm">
....
<form:select path="products" items="${products}" itemLabel="name" itemValue="id" multiple="true"/>
....
</form:form>

It's probably due to the fact that the list of selected products doesn't contain the same instances as the complete list of displayed products.
The tag compares products with equals(), and you have not overridden equals() (and hashCode()) in your Product class.
So even if the selected products contain the Product with the name "foo", and the complete list of Product also contains a Product with the name "foo", those products are not equal, and Spring thus doesn't know they're the same product, and that this product should thus be selected.

Related

Join Column between entities get NULL value instead of parent entity id number

I am Using Spring Boot on Java to create user's order on his checkout. A new Orders object is created which has a Linked Set of Items. Those items are user's cart contents.
Order is created, but its set of Items is null. The set size is 0. I checked that in JUnit tests. Can you help me to find out what is wrong? Maybe I have defined entities incorrectly? Have a look at the picture of the database:
And check the entities, Orders:
#Entity
public class Orders {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime submitedAt;
#NotEmpty
private String orderName;
#NotEmpty
#Column(name="`User`")
private String username;
#Enumerated(EnumType.STRING)
#Column
private OrderStatus status;
#OneToMany(mappedBy = "orders", cascade = { CascadeType.ALL}, fetch = FetchType.LAZY)
private Set<Item> items;
Item:
#Entity
public class Item {
#Id
private Integer id;
#Column(name="`NAME`")
private String dishName;
#Column(name = "`DESCRIPTION`", length = 2000)
private String dishDescription;
#Column(name = "`QUANTITY`")
private Integer quantityInCart;
#Column(name = "`USER`")
private String username;
#ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinColumn(name = "ORDERS_ID")
private Orders orders;
How to do entities relation correctly? Should it be one direction or bi-directional relationship?
What are differences of these relations? And what kind of relationship I should use? Why?
I was doing JUnit tests for the Orders service methods. It turns out that it can create orders. And Order items from user's cart.
But when it is time to show order (GetMapping) then it returns Orders entity with empty items set.
I think it happens because JPA cannot find foreign key of items for its designated order. It is null.
Why is it null?
And this is the service method that creates such order by user request:
#Transactional
public ResponseEntity<String> createOrder (String username) {
User user = userService.findByUsername(username);
List<CartItem> items = cartRepo.findByUser(user);
if(items.size() > 0) {
Orders newOrder = new Orders();
Set<Item> orderItems = new LinkedHashSet<>();
for(CartItem item : items) {
// new Item(Integer id, String dishName, String dishDescription, Integer quantityInCart, String username)
Item orderItem = new Item(item.getId(), item.getDish().getName(),
item.getDish().getDescription(), item.getQuantity(), item.getUser().getUsername());
orderItems.add(orderItem);
}
newOrder.setItems(orderItems);
newOrder.setOrderName(user.getUsername()+"'s order");
newOrder.setStatus(OrderStatus.SUBMIT);
newOrder.setSubmitedAt();
newOrder.setUsername(username);
orderDao.save(newOrder);
cartService.removeAllUserProducts(username);
LOG.info("[{}]: A new order is created successfully.", username);
return new ResponseEntity<String>("A new order is created successfully.", HttpStatus.CREATED);
}
//...
}
I tried to do one direction relationship for other entities and it really created foreign keys on joined column fields. But I want to find out why my bidirectional way of joining is wrong. Maybe someone who really knows can explain.
The Order class should be like this:
#Entity
public class Orders {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime submitedAt;
#NotEmpty
private String orderName;
#NotEmpty
#Column(name="`User`")
private String username;
#Enumerated(EnumType.STRING)
#Column
private OrderStatus status;
#OneToMany(cascade = { CascadeType.ALL}, fetch = FetchType.LAZY, orphanRemoval = true)
#JoinColumn(name="ORDERS_ID")
private Set<Item> items;
And Item class without Orders class and its ManyToOne relationship.
Now relationship is unidirectional. Item entity has foreign keys column name ORDERS_ID that has id's of Orders for which Items belong.

Can I get the list of objects in relation #OneToMany?

I've got 2 classes: Device and Category. 1 Device can have 1 assigned category, but 1 category can have assigned many different devices.
#Entity
#Data
#Table(name = "devices")
public class Device implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#Column(name="amount_of_items")
private Integer amountOfItems;
private BigDecimal price;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "category_id")
private Category category;
public Device(String name, String description, Integer amountOfItems, BigDecimal price, Category category){
this.name = name;
this.description = description;
this.amountOfItems = amountOfItems;
this.price = price;
this.category = category;
}
public Device() {}
}
#Entity
#Data
#Table(name = "categories")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#OneToMany(mappedBy = "category", fetch = FetchType.EAGER)
private List<Device> devices = new ArrayList<>();
public Category(String name, String description){
this.name = name;
this.description = description;
}
public Category() { }
}
Can I get the actual list of devices for one Category? The below code returns me a null list of devices:
Category category = new Category("Urzadzenia AGD", "tylko dla klientow premium");
categoryRepository.save(category);
Device device = new Device("pralka", "samoobslugowa", 50, new BigDecimal("220"),
category);
deviceRepository.save(device);
System.out.println(category.getDevies()) ---> returns NULL
Can I do it by calling a getter like above?
save method already return value after save in Database you can use this
Category category = new Category("Urzadzenia AGD", "tylko dla klientow premium");
category= categoryRepository.save(category);
Device device = new Device("pralka", "samoobslugowa", 50, new BigDecimal("220"),
category);
deviceRepository.save(device);
System.out.println(category.getDevies())
and you must be make setter and getter method in your class
after this you have problem stackover flow exciption becouse the all device called category and categore call Devices
you can used #JsonIgnore annotation
Like this :
#OneToMany(mappedBy = "category", fetch = FetchType.EAGER)
#JsonIgnore
private List<Device> devices = new ArrayList<>();

JPA - How to create entities where EntityA saves list ids of another table

I have an EntityA , and EntityB.
EntityB is a master table.
EntityA can have multiple id's of Entity B. So A column of EntityA should hold list/set of ids of EntityB.
I should be able to query EntityA, to get list of Ids of EntityB.
Note: Many rows in EntityA can refer to same id of EntityB
I tried below, but it I don't see column
#OneToMany(mappedBy = "todo")
private List<ObjectStore> store = new ArrayList<>();
Please can I ask how to do this using Spring JPA.
EDIT:
#Entity
public class Dept {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull(message = "name is mandatory")
private String name;
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;
}
}
and
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull(message = "name is mandatory")
private String name;
#ElementCollection(targetClass=String.class)
#CollectionTable(name = "DEPT", joinColumns = #JoinColumn(name="id"))
private List<String> dept = new ArrayList<String>(4);
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;
}
}
I observed that DEPT column got added to dept table. This is unwanted.
Use Case: Employee can hold list of departments. Many employee records, should be able to have same dept references.
You should change table name from "DEPT". Because #CollectionTable will create another embedded table with given name. In you case dept is already there so it will create new column in Dept.
// Employee Class
#ElementCollection(targetClass=String.class)
#CollectionTable(name = "DEPT_EMPLOYEE_MAPPING", joinColumns = #JoinColumn(name="Employee_id"))
#MapKeyJoinColumn(name="Dept_Id")
private Map<Dept,DeptEmployeeRelationData> depts;
//Dept class
#ElementCollection
#CollectionTable(name="DEPT_EMPLOYEE_MAPPING",joinColumns=#JoinColumn(name="Dept_Id"))
#MapKeyJoinColumn(name="Employee_Id")
Map<Employee, DeptEmployeeRelationData> employees;
#Embeddable
class DeptemployeeRelationData {
#Column(name="createdAt")
DateTime createdAt;
}
Your mapping is many to many.
Hope this will work!
I used
#ManyToMany
#OrderColumn
private List<String> dept = new ArrayList<String>(4);
and working as per my requirement
DEPT, EMPLOYEE , EMPLOYEE_DEPT created

Shared Primary Key between two Entities Not Working

I have created two Entities namely Teacher and Detail, the code snippet is shown below
Teacher.java
#Entity
#Table(name = "teacher")
public class Teacher implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "age")
private int age;
#OneToOne(mappedBy = "teacher", cascade = CascadeType.ALL)
private Detail detail;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
//getter and setter
}
Detail.java
#Entity
#Table(name = "detail")
public class Detail implements Serializable {
#Id
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private Teacher teacher;
#Column(name = "subjects")
private String subjects;
public Detail() {
}
public Detail(String subjects) {
this.subjects = subjects;
}
//getter and setter
}
I am trying to achieve one to one mapping with the shared primary key concept
but when i execute the controller, only Teacher table is updating with the value
try {
Teacher teacher=new Teacher("xyz",23);
Detail detail=new Detail("Java,c,c++");
teacher.setDetail(detail);
session.beginTransaction();
session.save(teacher);
session.getTransaction().commit();
model.addAttribute("added", "data inserted");
session.close();
}
After executing only Teacher table is updated with the specified values.Detail table is still showing empty
It does not work exactly like that. You still need the id field in your Detail, so add:
#Id
private long id;
to your Deatail class.
And - as comment suggests - replace the #Id annotation in field Teacher to #MapsId. This way the id of Teacher is mapped to the id of Detail BUT ONLY if you also set the teacher to the detail - you always need to set both sides of relationship - like:
teacher.setDetail(detail);
detail.setTeacher(teacher);

Select on Northwind database using JPA and JDBC Template

I would like to perform select statement on Northwind database like this bellow.
select distinct b.*, a.CategoryName
from Categories a
inner join Products b on a.CategoryID = b.CategoryID
where b.Discontinued = 'N'
order by b.ProductName;
I have two problems regarding this operation :
I have created POJO for tables categories and products like bellow
Table Products
#Entity
public class Products {
#Id
private Long productid;
private String productname;
private Long supplierid;
#ManyToOne
#JoinColumn(name = "categories", referencedColumnName = "categoryid")
private Categories categoryid;
private String quantityperunit;
private Double unitprice;
private Long unitsinstock;
private Long unitsonorder;
private Long reorderlevel;
private String discontinued;
Table Categories
#Entity
public class Categories {
#Id
private Long categoryid;
private String categoryname;
private String description;
private String picture;
Now I have no idea how to write rowmapper for this tables (please find below ????)
private static final RowMapper<Products> productsRowMapper = (rs, rowNum) ->{
Products products = new Products();
products.setProductid(rs.getLong("ProductID"));
products.setProductname(rs.getString("ProductName"));
products.setSupplierid(rs.getLong("SupplierID"));
products.setCategoryid(rs.?????
products.setQuantityperunit(rs.getString("QuantityPerUnit"));
products.setUnitprice(rs.getDouble("UnitPrice"));
products.setUnitsinstock(rs.getLong("UnitsInStock"));
products.setUnitsonorder(rs.getLong("UnitsOnOrder"));
products.setReorderlevel(rs.getLong("ReorderLevel"));
products.setDiscontinued(rs.getString("Discontinued"));
return products;
};
the second problem is that I don't know if the annotations on the column categoryid in the table products are correct?
After correction
#Repository
public class JdbcProductsDao implements ProductsDao{
private final JdbcTemplate jdbcTemplate;
#Autowired
public JdbcProductsDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static final RowMapper<Products> productsRowMapper = (rs, rowNum) ->{
Products products = new Products();
products.setProductid(rs.getLong("ProductID"));
products.setProductname(rs.getString("ProductName"));
products.setSupplierid(rs.getLong("SupplierID"));
products.setCategoryid(new Categories(rs.getString("CategoryName")));
products.setQuantityperunit(rs.getString("QuantityPerUnit"));
products.setUnitprice(rs.getDouble("UnitPrice"));
products.setUnitsinstock(rs.getLong("UnitsInStock"));
products.setUnitsonorder(rs.getLong("UnitsOnOrder"));
products.setReorderlevel(rs.getLong("ReorderLevel"));
products.setDiscontinued(rs.getString("Discontinued"));
return products;
};
public Products findByProductName(String productname) {
String sql = "SELECT * FROM products WHERE ProductName = ?";
return jdbcTemplate.queryForObject(sql, productsRowMapper, productname);
}
public List<Products> sortByProductName(){
String sql = "SELECT * FROM products order by ProductName asc";
return jdbcTemplate.query(sql, productsRowMapper);
}
Table Categories
#Entity
public class Categories {
#Id
private Long categoryid;
#Column(name = "CategoryName")
private String categoryname;
private String description;
private String picture;
#OneToMany(mappedBy="categoryid")
private List<Products> products;
Table Products
#Entity
public class Products {
#Id
private Long productid;
#Column(name = "ProductName")
private String productname;
private Long supplierid;
#ManyToOne
private Categories categoryid;
private String quantityperunit;
private Double unitprice;
private Long unitsinstock;
private Long unitsonorder;
private Long reorderlevel;
private String discontinued;
Now I have no idea how to write rowmapper for this tables (please find
below ????)
You have to set an Object like this :
products.setCategoryid(new Categories(rs.getString("a.categoryname"));
I assume you have an constructor Categories(String categoryname)
Note : If you want to get more information, you have to change your query and your constructor as well.
the second problem is that I don't know if the annotations on the
column categoryid in the table products are correct?
I think there are no need to use #JoinColumn(name = "categories", referencedColumnName = "categoryid") just use :
#ManyToOne
private Categories categoryid;
In your Categories entities add this :
#OneToMany(mappedBy="categoryid")
List<Products> products;

Resources