I have two entities lets call them Categories and Products. These two entities are mapped by a many to many relationship.
My problem is that i am trying to get category information from products. Trying this results in empty categories.
This is my code :
PersistenceEntity
#MappedSuperclass
public class PersistenceEntity implements Serializable {
private static final long serialVersionUID = 4056818895685613967L;
// Instance Variables
#Id
#Column(unique = true)
#GeneratedValue(strategy = GenerationType.TABLE)
protected Long id;
#JsonIgnore
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
protected Date creationDate = new Date();
...Getters and Setters omitted for brevity
}
Category
#Entity
#Table(name = "category")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Category extends PersistenceEntity{
private static final long serialVersionUID = 1L;
#Column(nullable = false)
private String categoryName;
#Column(nullable = false)
private Boolean active;
#Column(nullable = true)
private String picture;
#JsonIgnore
private MetaData metadata;
#ManyToMany(fetch = FetchType.EAGER,mappedBy = "categories")
private Set<Product> products;
...Getters and Setters omitted for brevity
}
Product
#Entity
#Table(name = "products",uniqueConstraints = { #UniqueConstraint(columnNames = "productCode")})
#JsonIgnoreProperties(ignoreUnknown = true)
public class Product extends PersistenceEntity {
private static final long serialVersionUID = 8727166810127029053L;
#Column(name = "product_name")
private String name;
private String productImageUrl;
#JsonIgnore
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name="category_products",
joinColumns={#JoinColumn(name="product_id", unique = false)},
inverseJoinColumns={#JoinColumn(name="category_id", unique = false)})
private Set<Category> categories;
...Getters and Setters omitted for brevity
}
ProductServiceImplementation
#Service
public class ProductService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private ProductRepository productRepository;
public List<Product> getProductsByShopId( Long id) {
List<Product> productList = new ArrayList<>();
productList = productRepository.findByShopId(id);
return productList;
}
public Set<Long> getCategoryIds(List<Product> products){
Set<Long> categoriesIDs = new HashSet<Long>();
for (Product product : products) {
product.getCategories().forEach(category -> {
categoriesIDs.add(category.getId());
});
}
return categoriesIDs;
}
}
The problem is getting the categoryIds that are mapped to the list of products.
How can i get CategoryIds from Product. My getCategoryIds function returns empty always
public Set<Long> getCategoryIds(List<Product> products){
Set<Long> categoriesIDs = new HashSet<Long>();
for (Product product : products) {
product.getCategories().forEach(category -> {
categoriesIDs.add(category.getId());
});
}
return categoriesIDs;
}
Related
Here is my database structure:
When I make a REST call to user_product with an intent to update the product value I keep on getting a null pointed exception. My assumption is that the problem lies in ServiceImpl though no matter what I change the error still consists.
My serviceImpl:
public void update(UserProductVO userProductVO) {
UserProduct userProduct = new UserProduct();
userProduct.setId(new UserProductId(userProductVO.getProduct().getId(), userProductVO.getUser().getId()));
userProduct.setUser(userProductVO.getUser());
userProduct.setProduct(userProductVO.getProduct());
UpdatedProduct updatedProduct = new UpdatedProduct(userProductVO.getAmountOfNewProducts());
updatedProductRepository.save(updatedProduct);
userProduct.getUpdatedProducts().add(updatedProduct);
userProductRepository.save(userProduct);
Product product = productRepository.getById(userProductVO.getProduct().getId());
product.setAmount(product.getAmount() + userProductVO.getAmountOfNewProducts());
productRepository.save(product);
}
Eror log says that the problem is here:
userProduct.getUpdatedProducts().add(updatedProduct)
I would appreciate any kind of clue where I might be messing up. Thanks in advance.
Edit:
My UserProduct class:
#Entity
#Table(name = "user_product")
public class UserProduct {
#EmbeddedId
private UserProductId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("userId")
#JsonBackReference(value = "userJ")
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("productId")
#JsonBackReference(value = "productJ")
private Product product;
#OneToMany(
mappedBy = "userProduct",
cascade = CascadeType.ALL,
orphanRemoval = true
)
#JsonManagedReference(value = "userProductJ")
private List<UpdatedProduct> updatedProducts;
public UserProduct() {
}
public UserProduct(UserProduct user, UserProduct product, int amountOfNewProducts) {
}
public UserProduct(User user, Product product, List<UpdatedProduct> updatedProducts) {
this.user = user;
this.product = product;
this.updatedProducts = updatedProducts;
}
..getters/setters/hashcode/equals
Edit2:
My UpdatedProduct class:
#Entity
#Table(name = "updated_product")
public class UpdatedProduct {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "amount_of_new_products")
private int amountOfNewProducts;
#Column(name = "updated_on")
private Date updatedOn = new Date();
#ManyToOne(fetch = FetchType.LAZY)
#JsonBackReference(value = "userProductJ")
private UserProduct userProduct;
public UpdatedProduct() {
}
public UpdatedProduct(int amountOfNewProducts) {
this.amountOfNewProducts = amountOfNewProducts;
}
You would have to initialize the UserProduct class with an empty list, not null:
public class UserProduct {
private List<UpdatedProduct> updatedProducts = new ArrayList<>();
// rest of the fields
}
All the annotations were omitted for brevity.
I use two class as models to build a JSON :
The productCreateRequestModel:
#Getter #Setter
public class ProductCreateRequestModel {
private Long id;
private String name;
private double price;
private int qty;
private String imgPath;
private CategoryRequestCreateProductModel category;
}
My CategoryRequestCreateProductModel
#Getter #Setter
public class CategoryRequestCreateProductModel {
private Long id;
private String name;
private String categoryKeyId;
}
I created 2 entities to manage categories and products.
#Entity
#Table(name="products")
#Getter #Setter
public class ProductEntity {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String productKeyId;
// many to one relationship with category
#ManyToOne
#JoinColumn(name = "category_id")
private CategoryEntity category;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private double price;
#Column(nullable = false)
private int qty;
private String imgPath;
}
And :
#Entity
#Table(name="categories")
#Getter #Setter
public class CategoryEntity {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#Column(length = 30, nullable = false)
private String categoryKeyId;
#Column(nullable = false)
private String name;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name="parent_id", nullable=true)
private CategoryEntity parentCategory;
// allow to delete also subcategories
#OneToMany(mappedBy="parentCategory", cascade = CascadeType.ALL)
private List<CategoryEntity> subCategories;
//Here mappedBy indicates that the owner is in the other side
#OneToMany(fetch = FetchType.EAGER, mappedBy = "category", cascade = CascadeType.REMOVE)
private List<ProductEntity> products;
}
This generated this table in the database.
In my controller:
public ProductRestResponseModel createProduct(#RequestBody ProductCreateRequestModel productCreateRequestModel) throws Exception {
ProductRestResponseModel returnValue = new ProductRestResponseModel();
if(productCreateRequestModel.getName().isEmpty() || productCreateRequestModel.getPrice() <= 0)
throw new ApplicationServiceException(ErrorMessages.MISSING_REQUIRED_FIELDS.getErrorMessage());
ModelMapper modelMapper = new ModelMapper();
ProductDto productDto = modelMapper.map(productCreateRequestModel, ProductDto.class);
ProductDto createdProduct = productService.createProduct(productDto);
returnValue = modelMapper.map(createdProduct, ProductRestResponseModel.class);
return returnValue;
}
In my Service I use the DTO:
#Override
public ProductDto createProduct(ProductDto productDto) {
ProductDto returnValue = new ProductDto();
if (productRepository.findByName(productDto.getName()) != null)
throw new ApplicationServiceException("Record already in Database");
ModelMapper modelMapper = new ModelMapper();
ProductEntity productEntity = modelMapper.map(productDto, ProductEntity.class);
String productKeyId = utils.generateProductKeyId(30);
productEntity.setProductKeyId(productKeyId);
ProductEntity storedProduct = productRepository.save(productEntity);
returnValue = modelMapper.map(storedProduct, ProductDto.class);
return returnValue;
}
My issue is when I send a post request with this object :
{
"name": "Pizza",
"price": 344.0,
"qty": 15,
"imgPath": "new/pathImage",
"category": {
"categoryKeyId": "23ume70Fu6yqyGUWfQkW110P4ko3gZ",
"name": "CatName"
}
}
When i send this request I obtain an error message : org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.app.ws.io.entity.ProductEntity.category -> com.app.ws.io.entity.CategoryEntity
My problem is that the Category already exists in the database and that i just need to set the foreign key in the product table
When running the application I get a org.hibernate.PersistentObjectException error from MockData. What is causing this? Are my cascadetypes wrong?
org.hibernate.PersistentObjectException: detached entity passed to
persist
The products are created and added after the categories, so the category should exist?
Product.java
#Entity
#Data
#Table(name = "product")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "manufacturer")
private String manufacturer;
#Column(name = "price")
private double price;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "category_id")
private Category category;
public Product(String name, String manufacturer, double price, Category category) {
this.name = name;
this.manufacturer = manufacturer;
this.price = price;
this.category = category;
}
public Product() {
}
}
Category.java
#Entity
#Data
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
private List<Product> products;
public Category(String name) {
this.name = name;
}
public Category() {
}
}
MockData.java
#Component
class MockData {
private final ProductRepository productRepository;
private final CategoryRepository categoryRepository;
#Autowired
public MockData(ProductRepository productRepository, CategoryRepository categoryRepository) {
this.productRepository = productRepository;
this.categoryRepository = categoryRepository;
loadData();
}
private void loadData() {
Category IT = new Category("IT");
Category beauty = new Category("Beauty");
Category food = new Category("Food");
categoryRepository.save(IT);
categoryRepository.save(beauty);
categoryRepository.save(food);
Product computer = new Product("Computer", "Dell", 5000, IT);
Product computer2 = new Product("Computer2", "HP", 5000, IT);
Product eyeliner = new Product("Eyeliner", "Chanel", 100, beauty);
Product hamburger = new Product("Angus", "Burger King", 100, food);
productRepository.save(computer);
productRepository.save(computer2);
productRepository.save(eyeliner);
productRepository.save(hamburger);
}
}
Changing mockdata to the following solved the problem:
#Component
class MockData {
private final ProductRepository productRepository;
private final CategoryRepository categoryRepository;
#Autowired
public MockData(ProductRepository productRepository, CategoryRepository categoryRepository) {
this.productRepository = productRepository;
this.categoryRepository = categoryRepository;
loadData();
}
private void loadData() {
Category IT = new Category("IT");
Category beauty = new Category("Beauty");
Category food = new Category("Food");
Product computer = new Product("Computer", "Dell", 5000, IT);
Product computer2 = new Product("Computer2", "HP", 5000, IT);
Product eyeliner = new Product("Eyeliner", "Chanel", 100, beauty);
Product hamburger = new Product("Angus", "Burger King", 100, food);
IT.setProducts(Arrays.asList(computer, computer2));
beauty.setProducts(Collections.singletonList(eyeliner));
food.setProducts(Collections.singletonList(hamburger));
categoryRepository.save(IT);
categoryRepository.save(beauty);
categoryRepository.save(food);
productRepository.save(computer);
productRepository.save(computer2);
productRepository.save(eyeliner);
productRepository.save(hamburger);
}
Products are created and added to categories before being saved.
I'm doing a registration and I have the fields
Nome:
Data de Nascimento:
Inscrição Estadual:
Nome Responsável:
CPF Responsável:
Cep:
Bloco:
Número:
when i saving, I can not write data from the PessoasEnderecos class, the other data is recording normal. I'm getting all the data on the screen so much that I debugged the browser to see ..
It shows no error. Does anyone know what I'm missing ??
my class Pacientes
#Entity
#Table(name = "pacientes", schema = "sau")
public class Pacientes implements Serializable {
private static final long serialVersionUID = 5776384003601026304L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idPaciente")
private Long idPaciente;
#JoinColumn(name="idPessoa")
#ManyToOne(cascade = CascadeType.ALL)
private Pessoas pessoa;
#Column(name = "nomeResponsavel")
private String nomeResponsavel;
#Column(name = "cpfResponsavel")
private String cpfResponsavel;
public Pacientes() {
}
//gets and sets
}
my class Pessoas
#Entity
#Table(name = "pessoas", schema="glb")
public class Pessoas implements Serializable {
private static final long serialVersionUID = -4042023941980758267L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
private Long idPessoa;
#Temporal(TemporalType.DATE)
private Date dataNascimento;
private String inscricaoEstadual;
private String inscricaoMunicipal;
private String nome;
public Pessoas() {
}
//gets and sets
}
#Entity
#Table(name = "pessoas_enderecos" ,schema="glb")
public class PessoasEnderecos implements Serializable {
private static final long serialVersionUID = -2560542418318988673L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idPessoaEndereco;
private String bloco;
private String cep;
private String numero;
#JoinColumn(name="idPessoa")
#ManyToOne(optional = false, cascade = CascadeType.ALL)
private Pessoas pessoa;
public PessoasEnderecos() {
}
//gets and sets
}
my methods
class Controller
#RequestMapping(method = RequestMethod.POST, value = "/pacientes")
public Pacientes cadastrarPacientes(#RequestBody Pacientes pac) {
return pacientesService.cadastrar(pac);
}
class service
public Pacientes cadastrar(Pacientes pacientes){
return pacRepository.save(pacientes);
}
class repository
public interface PacientesRepository extends JpaRepository<Pacientes, Integer> {
}
You should also add the linkage #OneToMany in Pacientes:
public class Pacientes implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "pessoa")
#PrimaryKeyJoinColumn
private List<PessoasEnderecos> pessoasEnderecos = new ArrayList<>();
Update:
and your JSON should be something like this:
{
"nomeResponsavel": "abc",
"pessoasEnderecos": [
{
"bloco": "sdds",
"cep": "sdasdsad",
"numero": "sdasdsa"
}
]
}
I have two table Orders and OrderItem as below:
#Entity
#Table(name = "orders")
public class Order implements Serializable {
#Id
#GeneratedValue
private Integer orderID;
#Column(nullable = false)
private Date orderDate;
#ManyToOne(cascade = CascadeType.ALL)
private User user;
#OneToMany(cascade = CascadeType.ALL)
private Set<OrderItem> orderItems = new HashSet<OrderItem>();
public Order() {
}
public Order(Date orDate, User currentUser) {
this.orderDate = orDate;
this.user = currentUser;
}
public Set<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(Set<OrderItem> orderItems) {
this.orderItems = orderItems;
}
//getter/setters for orderDate, user
And
#Entity
public class OrderItem implements Serializable {
#Id
#GeneratedValue
private Integer id;
#ManyToOne(cascade = CascadeType.ALL)
private Book book; // F.K to Book table
#Column(nullable = false)
private int quantity;
#Column(nullable = false)
private double totalPrice;
public OrderItem() {}
public OrderItem( Book currentBook, int qty, double totalPrice) {
this.book = currentBook;
this.quantity = qty;
this.totalPrice = totalPrice;
}
//getter/setters
And here i initialize them to store in database:
#Transactional
public void storeOrderInDB() {
order = new Order(currentDate(), currentUser); //date,user
orderService.addOrder(order);
OrderItem orderItem = new OrderItem();
orderItem.setBook(currentBook);
orderItem.setQuantity(qty);
orderItem.setTotalPrice(getTotalCost(qty, unitPrice));
orderItemService.addOrderItem(orderItem);
}
This is the result:
Orders:
OrderID: 5, OrderDate: "2015-04-25 23:11:16", userId: 1
OrderItem:
id:2 , quantity:1 , totalPrice:5000 , bookId:5 , order_orderID: null
Why order-orderID is null?
I need it to be not null.
In Order Entity You have declared
#OneToMany(cascade = CascadeType.ALL)
private Set<OrderItem> orderItems = new HashSet<OrderItem>();
Above declaration says that you foreign-key is maintain by Order Entity ,
To resolve your problem
#Transactional
public void storeOrderInDB() {
Order order = new Order(currentDate(), currentUser); //date,user
OrderItem orderItem = new OrderItem();
orderItem.setBook(currentBook);
orderItem.setQuantity(qty);
orderItem.setTotalPrice(getTotalCost(qty, unitPrice));
//orderItemService.addOrderItem(orderItem);
Set<OrderItem> orderItemSet=order.getOrderItems();
orderItemSet.add(orderItem);
order.setOrderItems(orderItemSet);
orderService.addOrder(order);
}
Hope this will resolve your problem
Thanks!