Error on JPA many-to-many relationship between entity table and join table - spring

I want a many-to-many relationship between an entity table and a join table. Invoices consist of a set of subscriptions. A subscription can be a part of multiple invoices (e.g. monthly subscription). Subscriptions consist of a user and a service. I am already using the subscriptions table as a join table for the many-to-many relationship between users and services (e.g. a user can subscribe to multiple services and a single service has multiple users). I have a table, "invoice_subscription," with IDs for both the invoice and subscription. Every table has its own ID. Below is the relevant snippet in the invoice object:
#ManyToMany
#JoinTable(
name = "invoice_subscription",
joinColumns = #JoinColumn(name = "invoice_id"),
inverseJoinColumns = #JoinColumn(name = "subscription_id")
)
public Set<Subscription> getSubscriptions() {
return subscriptions;
}
I am using the following in the subscription object:
#ManyToMany(mappedBy = "subscriptions")
public Set<Invoice> getInvoices() {
return invoices;
}
For the above, I am receiving the error below:
org.hibernate.MappingException: Foreign key (FKfe5yu82iapjynsdyfitclkri4:invoice_subscription [subscription_id])) must have same number of columns as the referenced primary key (subscription [user_id,service_id])
When I switch to two "#JoinColumn" annotations with the IDs in the error, I get the following error:
org.hibernate.AnnotationException: A Foreign key refering com.example.model.Subscription from com.example.model.Invoice has the wrong number of column. should be 1
I agree with this, but it seems to contradict the previous error. I've read documentation, guides, and other questions, but I have not found any useful information. I'm clearly missing something obvious.

Related

Check ManyToOne eager and lazy relations for null

Suppose that a certain booking's invoice is null in the DB.
public class Booking {
#Id
private Integer id;
...
#ManyToOne(... fetch = FetchType.LAZY)
#JoinColumn(...)
private Invoice invoice;
}
It seems that a many-to-one lazy relation always creates a proxy object for booking.getInvoice(), while an eager relation would just return a null. I think I can check the booking.getInvoice().getId(), but for that I must be sure that the relation is lazy. I don't want to do that because it forces me to always track the relation fetch type in the client code.
What if I have a lot of existing code that checks null in 'eager mode' and I want to convert a certain relation to lazy? Do I have to convert all null checks for that relation as well?
I'd think that since the DB field is null then the JPA would be smart enough to not create the proxy object at all here, leaving the private field invoice null.
Is the double check for null and id the only way to go?
Invoice invoice = booking.getInvoice();
if (invoice != null && invoice.getId() > 0) {
...
}
Is there a fetch-type-independent way to check for null many-to-one children in JPA?

How to retrieve an Entity Object just with #Id (Proxy object), check if it exists and assign it to a #ManyToOne association

I have an entity Product which have many fields and associations (around 60).
And a table ProductView which has a #ManyToOne(fetch = FetchType.LAZY) association with Product.
Is there a optimal way to retrieve Product object and assign it to ProductView ?
If its used JPA findById(productId) or JPQL/EntityManager selects-> It will retrieve all products fields and associations
Product product = productRepository.findById(productId);
ProductView productView = new ProductView(product);
save(productView);
If its used JPA getOne -> It solves the problem but the Proxy can throw error if Product does not exists. And this error can not be handled because it happens at runtime.
Product product = productRepository.getOne(productId);
ProductView productView = new ProductView(product);
save(productView);
If a DTO is used or Interface which refers to the same Product Table -> We will get just an object with Id field, but a lot more processes will need to be added (Which I am not familiar with)
Delete foreign keys from ProductView table (#ManyToOne -> #Column) and simple assign productIds. But in this way, there will be no logic connection between tables.
ProductView DB
How usually developers avoid this problem ?
I don't understand what the problem is. Just use getOne approach and at the end of your method, use flush which will throw the constraint violation exception that you can handle. This is the way to go.

Delete Values from Join Table spring boot

I have two tables students and subjects. A student can have more than one subject and vice versa. I have two model classes and vave joined using Many to Many relationship in spring boot and JPA.My problem is how I can delete values from my join table. But I can't figure out how I can do delete from join table. For Student and Subject Model I delete comfortably using deleteById() function.This is my code:
#ManyToMany
#JoinTable(
name = "student_subject",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "subject_id"))
private Set<SubjectModel> subjects;
//and my repository Class
#Repository
public interface SubjectDao extends JpaRepository<SubjectModel, Integer> {}
You have to delete the corresponding objects form both sides of the link, and then save them.
myStudent.getSubjects().remove(mySubject);
mySubject.getStudents().remove(myStudent);
SubjectDao subjectDao = new SubjectDao();
subjectDao.save(mySubject);
Here another examle: Hibernate: delete many-to-many association
You have two table Student and Subject.
And I suppose you want is delete one of the subject from a student.
For that you should let jpa delete the row from subject and student-subject association table. And dont need to user SubjectRepository.
Take a look.
Student firstStudent=studentRepository.findById(1);
Set<SubjectModel> subs=firstStudent.getSubject();
subs.clear();
firstStudent.setSubject(subs);
studentRepository.save(firstStudent); // this method will delete the row from assiciation table as well as the subject table.

Is it possible to use one-to-many and many-to-one in the same entity?

I would like to modify the spring's rest tutorial. Link here
The tutorial has two entity: User and bookmark ( many bookmark can belong to one user. )
I would like to modify it a bit. I would like to create a user, question, answer entity - a user can have many questions, and a question can have many answers.
Is this possible?
How should the entity definition look like for the question entity?
The logic would be that a user could create quizzes. The quiz can contain questions, and those questions may have possible answers.
Any ideas how should the entities look like?
I would appreciate every idea.
Is it possible to use one-to-many and many-to-one in the same entity?
I assume your question is, can "questions entity" have one-to-many relationship with Answers entity and many-to-one relationship with User entity at the same time.
Yes, it is possible. Just, be careful while using annotation to map your entities each other, otherwise performance of your application will be seriously degraded. Use eager/Lazy fetch wisely. Print out the sql queries that spring-data-jpa/hibernate fires under the hood and analyze.
It is definitely possible.
User
#Entity
public class User {
// id and other attributes ommited
// User and Quiz has OneToMany bidirectional relationship. OP hasn't specified that but I think it makes more sense because a quiz most likely will need to know the user who created it.
#OneToMany (mappedBy="user", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<Quiz> quizes;
// ...
}
Quiz
#Entity
public class Quiz {
// id ommitted
#OneToMany
private List<Question> questions;
#ManyToOne
#JoinColumn(name = "user_id") //quiz table will have a column `user_id` foreign key referring to user table's `id` column
private User user;
// ...
}
Question
#Entity
public class Question {
// id ommitted
#OneToMany
#JoinColumn(name="question_id") // Question and Answer has one-to-many unidirectional relationship. `answer` table has a foreign key `question_id` referring to `question.id` column
private List<Answer> answers;
// ...
}
Answer
#Entity
public class Answer {
// ..more attributes
}
Note that:
the entity relationships also depend on your business logic.
If the owner of the bidirectional relationship is different, then your client code needs to adjust. jpa-joincolumn-vs-mappedby
If you want to design your table to be "clean" such that one entity table does not have a foreign key referring to another associated entity. You can create a join table, make the OneToMany relationship "feel" like a ManyToMany and use unique index to enforce the OneToMany. It is up to you. This wikibook page explains pretty well
This is absolutely not the only solution.

HQL JoinTable not accessible 2

I have a code like that
#ManyToMany(cascade = { CascadeType.ALL }) #JoinTable(name = "AssignedBook_Person", joinColumns = { #JoinColumn(name = "person_Id") }, inverseJoinColumns = { #JoinColumn(name = "book_Id") })
As you see my JoinTable name is AssignedBook_Person and i want to take some data from it with that code
List borrowedBook = session createQuery(" from AssignedBook_Person ")
.setCacheable(true).list();
But it gives this error "AssignedBook_Person is not mapped "
Does anybody have any idea how i can solve JoinTable problem.
Thanks
You cannot query directly database tables via HQL , because it does not operate to database tables - it operates to entities. That is main idea of object relational mapping.
Join table contains data about relation between Book and Person, so data can be fetched by selecting instances of one of those and then examining related entities.
If only raw data in join_table is needed, native query can be used:
session.createSQLQuery(SELECT person_id, book_id FROM AssignedBook_Person);

Resources