I am trying to save a JPA entity which has ManytoMany Relationship (Consumer and Product table) and OnetoOne relation with ConsumerDetailstable.Below are my entities
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
#Entity
public class Consumer {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
#JsonManagedReference
#OnToMany(mappedBy = "consumer")
private Set<ConsumerProduct> consumerProducts;
#OneToOne
private CustomerDetails consumerDetails;
}
#Entity
public class Product {
#Id
#GeneratedValue
private Long productId;
private String productCode;
#OneToMany(mappedBy = "product")
private Set<ConsumerProduct> consumerProducts;
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
#Entity(the join table)
public class ConsumerProduct {
#EmbeddedId
ConsumerProductKey id;
#JsonBackReference
#ManyToOne
#MapsId("id")
#JoinColumn(name = "id")
private Consumer consumer;
#ManyToOne
#MapsId("productId")
#JoinColumn(name = "product_id")
private Product product;
}
#Embeddable (forgein keys combined as embeded id)
public class ConsumerProductKey implements Serializable {
#Column(name="id")
private Long id;
#Column(name = "product_id")
private Long productId;
}
#Enitity (one to one relation table)
public class CustomerDetails {
#Id
#GeneratedValue
private Long consumerDtlId;
#OneToOne
private Consumer consumer;
private String city;
private String state;
private String country;
}
To save the entity am have just extended JPARepository and called save method
public class ConsumerRepository<Consumer> Implements JPARepository<Consumer, Long> {
#Override
public Consumer S save(Consumer entity) {
return save(entity);
};
}
I get java.lang.StackOverFlowError at save method.
Anything wrong with my Mappings ?
Question: Since this will be save operation and since Consumer Id is yet to be generated how do I assign to below Entities
ConsumerProduct.ConsumerProductKey (how do i assign Id of consumer table once it is inserted to join table ? will JPA take care of it)
CustomerDetails (how do i assign Id of consumer table once it is inserted to join table ? will JPA take care of it)
EDIT: I have updated the entity with JsonManagedReference and JsonBackedReference but still i have am facing stackoverflow error
It is due to Consumer trying to access ConsumerProduct and ConsumerProduct trying to access consumer entity and end up with StackOverflow error.
You should use #JsonManagedReference and #JsonBackReference annotation in consumer and ConsumerProduct respectivly.
Related
I have two entity table one category and other is subject
My category entity
#Entity
public class Category extends AuditableEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(unique = true)
private String name;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "description_id")
private CategoryDescription description;
#OneToMany( mappedBy = "category", cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Subject> subjects;
//getter and setter
}
And my Subject entity
#Entity
public class Subject extends AuditableEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(unique = true)
private String name;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "description_id")
private SubjectDescription description;
#ManyToOne(fetch = FetchType.EAGER)
private Category category;
//Getter and Setter
}
Category Repository
#Repository
#Transactional
public interface CategoryRepository extends
JpaRepository<Category, Integer> {
}
Subject Repository
#Repository
#Transactional
public interface SubjectRepository extends JpaRepository<Subject,
Integer> {
}
Category Controller
#RestController
#RequestMapping("/category/api/")
public class CategoryResource {
private final CategoryService categoryService;
private final SubjectService subjectService;
private final TopicService topicService;
public CategoryResource(CategoryService categoryService,
SubjectService subjectService, TopicService topicService) {
this.categoryService = categoryService;
this.subjectService = subjectService;
this.topicService = topicService;
}
#PostMapping("save")
public void saveCategory(#RequestBody Category category) {
categoryService.save(category);
}
I am using postman to save data. Problem is that after saving data to the category and subject table my subject table column category_id is null i can not established a relationship between them my sql structure and data is after saving data it shows like
Category table
Subject Table
category_id is NULL how to set category id i am trying many ways but couldn't find a solution.Please help me to solve this issue
It's great that you are learning spring boot!
To answer your question since the answer is pretty simple, your code is missing category in subject.
subject.setCategory(category);
Now this might cause you an exception, so make sure you save category before you persist subject.
Cheers!
I have 3 entity class defined as below:
#Entity
public class Rimorchio {
#Id
#GeneratedValue
private long idrimorchio;
#Column(unique = true)
private String targa;
// .... Getters and Setters
}
#Entity
public class Atk {
#Id
#GeneratedValue
private long idatk;
#Column(unique = true)
private String codice;
#Column(unique = true)
private String targa;
#OneToOne
private Rimorchio suggerito;
// .... Getters and Setters
}
#Entity
public class Trasportatore {
#Id
#GeneratedValue
private long idtrasportatore;
#Column(unique = true)
private String nometrasportatore;
#OneToMany(cascade = {CascadeType.PERSIST})
private List<Rimorchio> listarimorchi;
#OneToMany(cascade = {CascadeType.PERSIST})
private List<Atk> listaatk;
#OneToMany(cascade = {CascadeType.PERSIST})
private List<Autista> listaautisti;
// .... Getters and Setters
}
When I try to save in the database the Trasportatore class, i receive the following error:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance -
save the transient instance before flushing :
com.petroli.gestionefasipetroli.entities.Atk.suggerito ->
com.petroli.gestionefasipetroli.entities.Rimorchio
So, I have to save the Rimorchio instance before the Atk instance.
I have a structure with a Repository that extends JpaRepository and a Service that simply call
repository.saveAndFlush(trasportatore);
How can I decide the order of insertion into DB to avoid this problem? Or there is another solution (possibly avoiding manually cascading operations) to achieve this goal?
I've got following two tables:
Customer
id
name
Order
id
product_name
customer_id
with a 1 to 1 relation
and java entities:
#Data
public class Customer{
#Id
private Long id;
private String name;
}
#Data
public class Order{
#Id
private Long id;
#Column("id")
private Customer customer; //i want to somehow map this
private String productName;
}
and a controller
#Controller
public class MyController{
//...
#GetMapping("/")
public String getmap(Model m){
System.out.println(repository.findAll()) //prints "nullrows" due to wrong sql statement
return "mytemplate";
}
}
my current issue is, that spring is executing following sql statement:
SELECT Order.id, Order.product_name, Customer.id, Customer.name
FROM Order LEFT OUTER JOIN Customer ON Customer.id = Order.id
what i actually want is to join on Customer.id = Order.customer_id while leaving the classes as they are i.e. the customer reference needs to stay in order.
i've tried every annotation that i could find so far and have made no progress.
EDIT:
I am not allowed to use jpa/hibernate
One workaround is to do the following:
#Data
public class Customer{
#Id
private Long id;
private String name;
}
#Data
public class Order{
#Id
private Long customerId;
private Long id;
#Column("id")
private Customer customer; //i want to somehow map this
private String productName;
}
causing this to automatically join on Customer.id = Order.customer_id
This does not look like a good fix however.
You can use #OneToOne and #JoinColumn annotations for your One-to-One relationship:
#Data
public class Customer{
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id", referencedColumnName = "id")
private Order order;
}
#Data
public class Order{
#Id
#Column(name = "id")
private Long id;
#Column(name = "product_name")
private String productName;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id", referencedColumnName = "id")
private Customer customer;
}
OK, so I've designed a basic CRUD an an exercise. It has 2 tables Jobs and Employees. I'm trying to create a many to one relationship, but when I click the link to go to the Employee Entry page it throws an error that kicks off with the #ManyToOne referencing an Unknown Entity.
Here is what I've got in my Employees.java
String jobName;
#ManyToOne(fetch=FetchType.EAGER)
#Fetch(value = FetchMode.JOIN)
#JoinColumn(name = "Job_Name")
#Column (name='jobName')
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
Any idea what i"m doing wrong and how to resolve this?
As per your comment,i think you can define relationship between these two entities like below.
#Entity
#Table(name="employee")
class Employee{
#Id
#GeneratedValue
private Integer id;
#ManyToOne
#JoinColumn(name = "job_name")
private Job job;
// other column and getter and setter
}
#Entity
#Table(name="job")
class Job{
#Id
#GeneratedValue
private Integer id;
#Column(name="job_name")
private String jobName;
//provide other column and getter setter
}
I have the following two classes, one ReqCandAssociation can have many Comments and it is mapped like so. I need to figure out a way that when I delete a ReqCandAssociation it deletes all of its associated comments. Thanks
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#ManyToOne
#PrimaryKeyJoinColumn(name="candidateId", referencedColumnName="id")
private Candidate candidate;
#ManyToOne
#PrimaryKeyJoinColumn(name="jobId", referencedColumnName="id")
private JobReq jobReq;
public ReqCandAssociation(){
}
Second class
#Entity
#Table(name="comment")
public class Comment {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="commentText")
private String commentText;
#Column(name="commentDate")
private Date commentDate;
#ManyToOne
#PrimaryKeyJoinColumn(name="reqCandAssociationId", referencedColumnName="id")
private ReqCandAssociation reqCandAssociation;
#ManyToOne
#PrimaryKeyJoinColumn(name="userId", referencedColumnName="id")
private User user;
Change this to the following, i'm making it bidirectional mapping.
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#OneToMany(cascade = { CascadeType.ALL }) //this is added here.
#JoinColumn(name ="reqCandAssociationId")
private Set<Comment> comments;
-----
Readup more on the cascade options. All cascade types are all|none|save-update|delete|all-delete-orphan|delete-orphan
The cascade all will delete all the comments associated to this class.