I have 2 very simple POJOs and i have just one to one mapping between them.
contact.java
comment.java -- it has foreign key column to the contact.java
the code i have written is below.
contact.java
#OneToOne(optional= false,cascade = CascadeType.ALL, mappedBy="contact", fetch=FetchType.LAZY)
#org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
private Comment mComment;
comment.java
#OneToOne(fetch = FetchType.LAZY,cascade=CascadeType.ALL )
#JoinColumn(name="EW_CNTC_ID")
private Contact contact;
i am setting comment into contact pojo and finally i am saving contact.java
if i keep #OneToOne(optional= false, i am getting dataintegrityexception, constraintvoilationexception
if i changed #OneToOne(optional= true, then it is working.
i think that if optional is false, it is trying to insert contact, it find comment it is trying to insert comment, but it has reference to contact it has to set the foreign key without inserting contact it cannot keep foreign key ..
if optional true the contact can be inserted without comment and PK generated for contact and tat is set in the foreign key column of the contact.--- anyway this issue is solved.
one more thing i am loading contacts i need to lazy load the comments, it is no where working can some one help on this, i strictly need lazy loading of comment because of performance problm.
Thanks in advance.
We have this issue in hibernate 3. Hibernate 4 fixed this issue.
If you want to load only contacts not comments then try like this(Imply change it to manytoone relation).
#ManyToOne(fetch=FetchType.LAZY)
private Comment mComment;
Related
I have a simple unidirectional ManyToOne relationship on an entity, which unfortunately is defined in a schema I cannot change.
It is defined as follows
#Entity
#Table(name="Profile")
...
public class Profile{
#ManyToOne
#JoinColumn(name="usr_id", nullable=false, updatable=false)
private User usr;
...
and all is well. The relationship is enforced with a foreign key in the db, hence the nullable = false and updatable = false. There is no mention of the profiles in user.
When I try to delete a Profile, hibernate also tries to delete the User entity, which is parent to other relationships and therefore fails. I have no CascadeType annotations anywhere.
My intent is to have a simple reference to the user using this profile in the usr field. This is a unidirectional relationship. The user entity should not be affected whenever I delete a profile.
This appers to be achievable when the usr field may be dereferenced before delete (I can see in the hibernate generated sql that hibernate attempts to set the field to null before deletion) - however that fails because of the foreign key.
Is what I'm trying to do achievable? If so, how?
(I'm using spring data on top of hibernate, if that is relevant.)
further Infos: I have tried optional=false, and it leads to the delete the parent entity behaviour. I have tried all fitting combinations of CascadeTypes, #OnDelete with NO_ACTION (still tries to delete the user) and defining a reverse but owned by user relationship - no success so far. On top of that, I tried the search function ;), which lead me to the conclusion that this is just my problem. If I missed an answered question, I'd appreciate a pointer in the right direction. Thanks.
Do you have some kind of other non-nullable association #ManyToOne or #OneToOne to the Profile entity? You can debug into the deletion process by setting a break point in e.g. the JDBC driver in e.g. Connection.prepareStatement and go down the stack frames to the cascading part to figure out why this cascading happens.
If all that doesn't help, please create a reproducing test case and submit an issue to the Hibernate issue tracker.
i tried finding similar issue here and i found this here
but it did not help much.
this here is the exact issue i have. Thing is the #OnDelete forces me to make a bidirectional relationship right? I would like to keep it unidirectional if possible.
What i want to do is delete a comment (child) from a post (parent);
every time i am trying to do that i receive this error
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`blogapp2`.`post_comments`, CONSTRAINT `FKrvgf8o4dg5kamt01me5gjqodf` FOREIGN KEY (`comments_id`) REFERENCES `comment` (`id`))
this is my code
the delete method
#GetMapping("/dashboard/showposts/deletecomment/{id}")
public String deleteComment(#PathVariable("id") Long id) {
commentService.deleteComment(id);
return "redirect:/admin/dashboard/showposts";
}
in Post
#OneToMany(cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
in Comment there is no reference to the Parent.
How can i delete the Comment from the database? i mention that cascade works with no issues so when i delete the parent all the children are deleted aswell.
Any help would be greatly appreciated !
L.E:I modified my handler method to look like this
#GetMapping("/dashboard/showposts/deletecomment/{id}")
public String deleteComment(#PathVariable("id") Long id) {
List<Comment> comments = commentService.findAll();
Comment comment = commentService.findBYId(id);
comments.remove(comment);
return "redirect:/admin/dashboard/showposts";
}
You can do it without creating bidirectional relationship but there is one caveat in doing so and I would come to that later, let's see how you can do that in unidirectional relationship.
First you need to specify the orphanRemoval=true on your entity relation
#OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
List<Comment> comments = new ArrayList();
// Now I am assuming you have equals and hash code methods are implemented in your comment class,
// So all you need to load the Comment Entity by its id and then have to call
Comment comment = dao.findById(id);
comments.remove(comment);
// This will delete the comment from table and will keep all comments as it is.
// Another way is to iterate the comments list and find matching Comment object (add the method in transaction)
#Service
class PostService {
#Transactional
public Comment deleteComment(Integer commentId) {
Post post = repository.findById(id);
List<Comment> comments = post.getComments();
Comment comment = comments.stream().filter(c -> c.getId().equals(commentId)).findAny()
.orElseThrow(() -> new IllegalArgumentException("Invalid comment id"));
comments.remove(comment);
return comment;
}
}
Caveats:
1. post.getComments() // will load all comments from database
2. comments.remove(comment) // will trigger additional INSERT statements
Why additional insert statements will be triggered?
When you use uni-directional mapping, JPA provider (hibernate) will create additional junction table and your relation becomes #ManyToMany at the background.
So it will first Delete all the entries from junction table passing associated post_id and then insert all the records back to junction table, leaving the record we deleted.
Then it will delete the entry from comment table, so its a performance penalty you have to pay using unidirectional relation.
By the error message, I assume that besides tables post and comments, you have a join table named post_comments.
If thats the case, hibernate is not aware of it. You should use not only #OneToMany but #JoinTable annotation as well in the commentsfield of Post class.
I just enabled the JPA validation in eclipse and in shows me some errors (The code is actually running fine).
I have an article entity and it holds a refrence to the next article and the previous entity (of the same type). The validator complains with the message:
Column "nextArticle" cannot be resolved on table "article"
What does this mean exactly? The SQL table has the columns as well. I tried also to map the variables to each other with the "mappedBy" and "JoinColumn" annotation, but was not able to resolve the validation error.
That's the class and validation error:
And that' the mapping:
Edit: Tried the suggestion from anttix: The columns in the table are named "nextArticle_id" and "prevArticle_id", so I came up with that code:
#OneToOne(mappedBy = "prevArticle")
#JoinColumn(name = "nextArticle_id")
public Article getNextArticle() {
return nextArticle;
}
#OneToOne(mappedBy = "nextArticle")
#JoinColumn(name = "prevArticle_id")
public Article getPrevArticle() {
return prevArticle;
}
But the validator complains now about the "mappedBy" annotation with the message:
In attribute 'prevArticle', the "mapped by" attribute 'nextArticle' has an invalid mapping type for this relationship.
Edit 2: I found the solution. I had to tell the validator the names of the columns in the actual database with the #Column annotation like this:
Eclipse can't find a column called prevArticle in the table. You should specifiy the column name for nextArticle and create a bidirectional relation with prevArticle to indicate that it does not need a foreign key column of its own.
#OneToOne
#JoinColumn(name = "next_id")
private Article nextArticle;
#OneToOne(mappedBy = "nextArticle")
private Article prevArticle;
You can omit the #JoinColumn from nextArticle if you want, but I would keep it there to make it clear which relation "owns" the foreign key column.
See also:
http://en.wikibooks.org/wiki/Java_Persistence/OneToOne
I'd like to remove entities from my table and have it auto-removed any entities that are childs of it.
Example:
class User {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval=true)
#OnDelete(action = OnDeleteAction.CASCADE)
List<Address> addresses;
}
When I remove a User that has no address, everything works fine. Also removing an address without removing the user works.
But: If I try to remove a user that has still some addresses, I'm getting org.hsqldb.HsqlException:
integrity constraint violation: foreign key no action; FK_ADDRESS_USER_ID table: ADDRESS
What might be wrong here?
Or is this not supported and I have to explicitly remove all contained Address objects first before deleting a user?
I believe you have a problem with a foreign key constraint. Use a DB tool like Aqua Data Studio or similar (you can probably also do this in your IDE, in Eclipse - Data Source Explorer view), to show the create script for your ADDRESS table. It should contain something like this:
ALTER TABLE TESTSCHEMA.ADDRESS
ADD CONSTRAINT FK1ED033D4E91AAFD9
FOREIGN KEY(FK_ADDRESS_USER_ID)
REFERENCES TESTSCHEMA.USER(ID)
ON DELETE CASCADE
The point being the ON DELETE CASCADE part in your case. If this is missing or is different, that probably is what is causing the problem. If the table is auto-generated by Hibernate, this constraint should be valid, but keep in mind that there are differences between databases. It could be that the table was generated before the Hibernate's #OnDelete annotation was added, so now you are getting the "foreign key no action" integrity constraint violation.
Not related to the issue, but do note that orphanRemoval=true will try to remove the address from the database, when it is removed from the collection in the User entity.
Also, check this out for details on Hibernate’s support for database ON DELETE CASCADE constraint.
I have the following scenario:
I have a system full of users. There is a desire to run contests for users who log into the site over a week or so. Therefore I needed to create a new Contest object which would contain both the entries and the winners.
I created something like this:
private Set<User>;
#OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
#JoinTable(name="contest_entries",
joinColumns = {#JoinColumn(name = "contest_fk", referencedColumnName="contest_id")},
inverseJoinColumns = {#JoinColumn(name = "user_fk", referencedColumnName="id")})
public Set<User> getEntries() {
return entries;
}
The idea being that a Contest can have multiple entries. Seems simple. It generates the following:
create table contest (contest_id numeric(19,0) identity not null, primary key (contest_id));
create table contest_entries (contest_fk numeric(19,0) not null, user_fk numeric(19,0) not null, primary key (contest_fk, user_fk));
alter table contest_entries add constraint FK7FBD0C65C4F120C2 foreign key (contest_fk) references contest;
alter table contest_entries add constraint FK7FBD0C656ABC75E3 foreign key (user_fk) references user_profile;
However, once a contest is over, the desire is to run another contest. When I attempt to create a new contest and have one of users who had entered previously enter again, I get a unique key constraint. Looking at the table DDL, it makes sense that it does.
So, in essence, I can't run two contests at the same time. I would also lose history of people entering the contests. That's not going to work. I need to be able to run two contests at once with the same users in different contests.
I'm new to JPA, so I have to believe I'm missing something obvious. The system already has a user table and it's populated full of users. There is a desire not to change that table structure. Any ideas on how to solve this? If it matters, the persistence implementation is Hibernate.
You actualy have a many-to-many relationship. So you should use the #ManyToMany annotation.