Regards,
Håkon
This is the stack:
org.hibernate.exception.ConstraintViolationException: Could not
execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2650)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2895)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:267)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:259)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:183)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:32
4)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:791)
at play.db.jpa.JPABase._delete(JPABase.java:73)
at controllers.CRUD.delete(CRUD.java:152)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:408)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:403)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:176)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:169)
at play.Invoker$Invocation.run(Invoker.java:187)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:149)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.j
ava:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206
)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a
parent row: a foreign key constraint fails (`charttr
aders`.`post_user`, CONSTRAINT `FKEEC7040A388562DE` FOREIGN KEY
(`Post_id`) REFERENCES `post` (`id`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1451)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 33 more
you have to reduce the cascading in the ManyToMany mapping. I suppose
you want to remove a thread and the posts, but not the Users, so your
mapping should look like
@ManyToMany(fetch = FetchType.LAZY, cascade =
{CascadeType.PERSIST, ... }) // all cascadeType-s but REMOVE
public User user;
(I assume your CascadeType is "ALL")
Note that if you delete a User, you will have to first nullify the
references from the posts to that user, using e.g.
JPA.em().query("update Posts set viewedBy = null where viewedBy.id =
?", user.getId());
Hope this helps
> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>
>
But it still complains. I probably need to do something similar to:
JPA.em().query("update Posts set viewedBy = null where viewedBy.id =
> ?", user.getId());
also here in this instance. My question is where is the best place to
do this? I see myself overriding a delete method in the Model but I
haven`t had success with that. Is the invoked controller method the
only point I can include this?
Thanks,
Håkon
> But it still complains. I probably need to do something similar to:
> JPA.em().query("update Posts set viewedBy = null where viewedBy.id =
>> ?", user.getId());
do you maybe have a reverse mapping from the User to the Posts? Or
from one Post to another?
> also here in this instance. My question is where is the best place to
> do this? I see myself overriding a delete method in the Model but I
> haven`t had success with that. Is the invoked controller method the
> only point I can include this?
how do you delete a Post at the moment? I would de-reference the Posts
before calling any delete method. Or do you use e.g. the CRUD module?
In that case I'm not entirely sure how things work, but I suppose
there must be a way to customize the controller actions, even for the
CRUD module
public String content;
public Date created;
public Date lastEdited;
@ManyToOne
public User user;
@ManyToOne
public Thread thread;
@ManyToMany(fetch=FetchType.LAZY, cascade=
{CascadeType.PERSIST, CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH})
public List<User> viewedBy = new ArrayList();
}
@Entity
public class User extends Model {
@Required
public String userName;
@Required
public String email;
@Required
public String password;
@Required
public Date signedUp;
public Blob avatar;
@ManyToOne
public UserGroup userGroup;
@OneToOne
public Location location;
@OneToMany
public List<Journal> journals;
public boolean isPasswordConfirmed(String passwordConfirm) {
if(password.equals(passwordConfirm)) return true;
else return false;
}
public void hashThePassword() {
password = Codec.hexSHA1(password);
}
@OneToMany(mappedBy="user", cascade=CascadeType.REMOVE)
public List<Post> posts;
public Long getNumberOfPosts() {
return Post.count("user = ?", this);
}
@Override
public String toString() {
return userName;
}
}
Yes, I`m using the CRUD module at the moment, and I can`t override it
because of the static methods. I can spend time making my own of
course. My concern though is that it should be possible to override a
method closer to the JPA delete logic.....? I don`t want to have logic
about deleting user references to posts in my future deleteThread
public method (I`ll do it if I have to of course :)).
Thanks,
Håkon
On Sat, Feb 19, 2011 at 11:13 PM, Manuel Bernhardt
are you trying to delete a whole Thread or a single Post?
You need to also not propagate the deletion cascade to the User of your Post:
@ManyToOne
public User user;
It's basically the same issue as with the viewedBy list: everything
that you map with a CascadeType.ALL will cause cascade deletion.
Also it looks like you have a reverse mapping from the users to the posts:
@OneToMany(mappedBy="user", cascade=CascadeType.REMOVE)
public List<Post> posts;
In that case you'll most likely be more successful deleting the Post
by removing it from that List, but I am not sure if the CRUD module
operates that way. Do you really need the reverse mapping? You also
can get the posts of a User by writing a finder method like this:
public static List<Post> getPosts() { Post.find("where user = ?", this); }
Thanks for your help Manuel!
Håkon
On Sun, Feb 20, 2011 at 1:37 PM, Manuel Bernhardt