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

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<>();

Related

HOW JOIN two tables JPQL

How create a join pageable USING JPQL in Class Movie with MovieLanguage?
The Class Movie as a relationship 1 to 1 with MovieLanguage.
Movie:
Entity
#Table(name = "tb_movie")
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private Double score;
private Integer count;
private String image;
public Movie() {}
public Movie(Long id, String title, Double score, Integer count, String image) {
this.id = id;
this.title = title;
this.score = score;
this.count = count;
this.image = image;
}
#OneToOne(cascade = CascadeType.ALL, mappedBy = "movie")
#JsonManagedReference
MovieLanguage movieLanguage;
/* getter and setter */
}
MovieLanguage:
#Entity
#Table(name = "tb_movie_language")
public class MovieLanguage {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String titleBrazil;
private String titleSpanish;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "movie_id")
#JsonBackReference
private Movie movie;
public MovieLanguage(){}
/* getter and setter */
}
Here is a JPQL example in MovieJoinRepository, but not working:
MovieJoinRepository:
public interface MovieJoinRepository extends JpaRepository<Movie, Long> {
#Query("SELECT obj FROM Movie obj INNER JOIN obj.movie_language mm WHERE obj.id = mm.id ")
Page<String> findAllPaged(Pageable pageable);
}
Thank you for you help!

JPA ManyToMany fails with "must have same number of columns as the referenced primary key"

I have three tables customer, product and sales. sales is the join table to store the customer's products as shown below:
customer, product and Sales tables
My Entities defined as described below:
Customer.java
#Entity
#Table(name="customer")
public class Customer {
#Id
#Column(name="c_id")
private String customerId;
#Column(name="customer_name")
private String customerName;
#ManyToMany
#JoinTable(
name = "sale",
joinColumns = #JoinColumn(name = "c_id"),
inverseJoinColumns = #JoinColumn(name = "p_id"))
private Set<Product> customerProducts = new HashSet<>();
}
Product.java
#Entity
#Table(name="product")
public class Product {
#Id
#Column(name="p_id")
private String productId;
#Column(name="product_name")
private String productName;
#Column(name="price")
private Double price;
// ... Setters & Getters
}
Sales.java
#Entity
#Table(name="sales")
public class Sales {
#EmbeddedId
private SalesPK salesId;
#Column(name="qty")
private Long qty;
// ... Setters & Getters
}
SalesPK.java
#Embeddable
public class SalesPK implements Serializable {
#Column(name = "c_id")
private String customerId;
#Column(name = "p_id")
private String productId;
public SalesPK() {}
public SalesPK(String customerId, String productId) {
this.customerId = customerId;
this.productId = productId;
}
}
CustomerRepository.java
#Repository
public interface CustomerRepository extends CrudRepository<Customer, String> {
#Query("select customer from Customer customer " +
"left join fetch customer.customerProducts " +
"where customer.customerName = :customerName")
public Customer getCustomerPurchasedProducts(String customerName);
}
My Spring boot application fail to start with following exception:
org.hibernate.MappingException: Foreign key (FK7wwx8x75009xqb1y0tawm8rty:SALES [p_id])) must have same number of
columns as the referenced primary key (SALES [c_id,p_id])
What am I missing here? I have followed the notes as described here in https://www.baeldung.com/jpa-many-to-many
UPDATE:
There is no issue with above solution, I have misspelled "sales" table in #ManyToMany declaration changing from "sale" to "sales" fixed the issue. Strange behavior why it didn't compline about missing table instead it complain about actual composite primary key definition.
Following code Fixed the issue:
#ManyToMany
#JoinTable(
name = "sales",
joinColumns = #JoinColumn(name = "c_id"),
inverseJoinColumns = #JoinColumn(name = "p_id"))
private Set<Product> customerProducts = new HashSet<>();
}
I would map these classes a bit differently:
#Entity
#Table(name="customer")
public class Customer {
#Id
#Column(name="c_id")
private String customerId;
#Column(name="customer_name")
private String customerName;
#OneToMany(mappedBy = "customer")
private Set<Sale> customerSales = new HashSet<>();
}
#Entity
#Table(name="product")
public class Product {
#Id
#Column(name="p_id")
private String productId;
#Column(name="product_name")
private String productName;
#Column(name="price")
private Double price;
}
#Entity
#Table(name="sales")
public class Sales {
#EmbeddedId
private SalesPK salesId;
#MapsId("customerId") // maps customerId attribute of embedded id
#ManyToOne
Customer customer;
#MapsId("productId") // maps productId attribute of embedded id
#ManyToOne
Product product;
#Column(name="qty")
private Long qty;
// ... Setters & Getters
}
#Embeddable
public class SalesPK implements Serializable {
#Column(name = "c_id")
private String customerId;
#Column(name = "p_id")
private String productId;
public SalesPK() {}
public SalesPK(String customerId, String productId) {
this.customerId = customerId;
this.productId = productId;
}
}

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);

Need solution for following scenario in Hibernate many to many mapping

Consider the tables where posts and tags exhibit a many-to-many relationship between each other.
The many-to-many relationship is implemented using a third table called post_tags which contains the details of posts and their associated tags.
Post Model
#Entity
#Table(name = "posts")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(max = 100)
#Column(unique = true)
private String title;
#NotNull
#Size(max = 250)
private String description;
#NotNull
#Lob
private String content;
#NotNull
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "posted_at")
private Date postedAt = new Date();
#NotNull
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "last_updated_at")
private Date lastUpdatedAt = new Date();
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "post_tags",
joinColumns = { #JoinColumn(name = "post_id") },
inverseJoinColumns = { #JoinColumn(name = "tag_id") })
private Set<Tag> tags = new HashSet<>();
public Post() {
}
public Post(String title, String description, String content) {
this.title = title;
this.description = description;
this.content = content;
}
// Getters and Setters (Omitted for brevity)
}
TAG Model
#Entity
#Table(name = "tags")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Size(max = 100)
#NaturalId
private String name;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
public Tag() {
}
public Tag(String name) {
this.name = name;
}
// Getters and Setters (Omitted for brevity)
}
Problem is
I tried to use an existing tags. and insert happened only on posts & posts_tags table.
Initially i'm Get tag(s) with tagName(s). Once you have the Tag object, you can set it in the Post object and save it.
Like this
Post post = new Post("Hibernate Many to Many Example with Spring Boot",
"Learn how to map a many to many relationship using hibernate",
"Entire Post content with Sample code");
// Create two tags
Tag tag1 = tagService.getTag("Spring Boot");
// Add tag references in the post
post.getTags().add(tag1);
postRepository.save(post);
If I do like that, entry is not available in post_tags table.
Tag Repository and Tag Service:
#Repository
public interface TagRepository extends JpaRepository<Tag, Long> {
#Query("select p from Tag p where p.name = :name")
Tag findByName(#Param("name") String name);
}
#Override
public Tag findByName(String name) {
return repository.findByName(name);
}

JPA - Join another entity by EmbeddedId with 2 columns

Basically. I have a ProductEntity, like this:
#Entity
#Table(name = "product", schema = "shop")
public class ShopProductEntity {
#EmbeddedId
private ProductEntityId id;
#Column(name = "product_name")
private String name;
#Column(name = "product_category_id")
private int categoryId;
#Column(name = "product_language_id")
private int languageId;
// TODO: Get category by categoryId and languageId.
private CategoryEntity category;
I have another CategoryIdentity:
#Entity
#Table(name = "category", schema = "shop")
public class CategoryEntity {
#EmbeddedId
private CategoryEntityId id;
#Column(name = "category_name")
private String name;
#Column(name = "category_url")
private String url;
It has an EmbeddedId like this:
#Embeddable
public class CategoryEntityId implements Serializable {
#Column(name = "category_id", nullable = false)
private int categoryId;
#Column(name = "language_id", nullable = false)
private int languageId;
public int getCategoryId() {
return categoryId;
}
public int getLanguageId() {
return languageId;
}
Now, every product has a category. Categories are unique by their id and language. The shop connects to a category by both the categoryId and languageId columns. How do I add the CategoryEntity to my ProductEntity so I can use the category's url value for my product?
I tried adding this to ShopProductEntity:
#ManyToOne
#JoinColumns({
#JoinColumn(name="categoryId", referencedColumnName="categoryId"),
#JoinColumn(name="languageId", referencedColumnName="languageId"),
})
private CategoryEntity category;

Resources