persistence@glassfish.java.net

Re: PreRemove ConcurrentModificationException

From: Greg Ederer <greg_at_ergonosis.com>
Date: Thu, 14 Jun 2007 16:12:54 -0700

Marina Vatkina wrote:
> Markus, Greg,
>
> In this particular case, the code starts with
> Object o = em.find(javaType, id);
>
> So merge is not needed at all.
>
Thanks Marina,

I'm afraid that was a bit of cruft that got in via copy-and-paste.

Cheers,

Greg

> thanks,
> -marina
>
> Markus Fuchs wrote:
>> Hi Greg,
>>
>> I can't see, why you should get a foreign key violation removing an
>> ArticlePlacement, since ArticlePlacement owns the the relationships
>> to Article and ArticleGroup. To only other relationship is a
>> uni-directional OneToMany between Article and ArticleGroup. But
>> neither Articles nor ArticleGroups are removed, correct?
>>
>> BTW, in
>>
>>> utx.begin();
>>> em.merge(o);
>>> em.joinTransaction();
>>> em.remove(o);
>>> utx.commit();
>>>
>> you should call the remove operation on the managed copy returned by
>> em.merge(o)
>>
>> Thanks,
>>
>> -- markus.
>>
>>> Where javaType is com.acadept.model.article.ArticlePlacement.
>>>
>>> Greg Ederer wrote:
>>>
>>>> Markus Fuchs wrote:
>>>>
>>>>> Hi Greg,
>>>>>
>>>>> That sounds like a bug to me. Could you send me your pojos and a
>>>>> small snipplet of your application code as a test case?
>>>>>
>>>>> You are talking about em.remove(article) and no @PreRemove in
>>>>> ArticlePlacement resulting in a foreign key violation, correct?
>>>>>
>>>> Actually, I get the fk violation when I em.remove(articlePlacement)
>>>> w/o the @PreRemove. Does this still sound like a bug, or is it
>>>> just my incorrect way of doing things?
>>>>
>>>> Code below.
>>>>
>>>> Cheers,
>>>>
>>>> Greg
>>>>
>>>> In my servlet:
>>>>
>>>> Object o = em.find(javaType, id);
>>>> responseMap.put("javaType", javaType);
>>>> responseMap.put("id", id);
>>>> utx.begin();
>>>> em.merge(o);
>>>> em.joinTransaction();
>>>> em.remove(o);
>>>> utx.commit();
>>>>
>>>>
>>>> /*
>>>> * Article.java
>>>> *
>>>> * Created on May 7, 2007, 2:15 PM
>>>> *
>>>> * To change this template, choose Tools | Template Manager
>>>> * and open the template in the editor.
>>>> */
>>>>
>>>> package com.acadept.model.article;
>>>>
>>>> import com.acadept.model.*;
>>>> import java.io.Serializable;
>>>> import java.util.ArrayList;
>>>> import java.util.Date;
>>>> import java.util.List;
>>>> import javax.persistence.CascadeType;
>>>> import javax.persistence.Column;
>>>> import javax.persistence.Entity;
>>>> import javax.persistence.GeneratedValue;
>>>> import javax.persistence.GenerationType;
>>>> import javax.persistence.Id;
>>>> import javax.persistence.ManyToOne;
>>>> import javax.persistence.OneToMany;
>>>> import javax.persistence.OneToOne;
>>>> import javax.persistence.PreRemove;
>>>> import javax.persistence.SequenceGenerator;
>>>> import javax.persistence.Temporal;
>>>> import javax.persistence.TemporalType;
>>>>
>>>> /**
>>>> * Entity class Article
>>>> * * @author gregederer
>>>> */
>>>> @Entity
>>>> public class Article implements Serializable
>>>> {
>>>> @Id
>>>> @GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
>>>> "ARTICLE_SEQ_GENERATOR")
>>>> @SequenceGenerator(name = "ARTICLE_SEQ_GENERATOR", sequenceName =
>>>> "ARTICLE_ID_SEQ")
>>>> private Long id;
>>>>
>>>> @ManyToOne
>>>> private ArticleCategory articleCategory;
>>>>
>>>> @OneToMany(mappedBy = "article", cascade=CascadeType.ALL)
>>>> private List<ArticlePlacement> articlePlacements = new
>>>> ArrayList<ArticlePlacement>();
>>>>
>>>> @Column(name="lead_in_image")
>>>> private String leadInImage;
>>>>
>>>> private String title;
>>>>
>>>> private String subTitle;
>>>>
>>>> @Column(name="lead_in", columnDefinition="text")
>>>> private String leadIn;
>>>>
>>>> @Column(columnDefinition="text")
>>>> private String body;
>>>>
>>>> @OneToOne
>>>> private AppUser poster;
>>>>
>>>> @Column(name="publication_date")
>>>> @Temporal(TemporalType.DATE)
>>>> private Date createdDate;
>>>>
>>>> /** Creates a new instance of Article */
>>>> public Article()
>>>> {
>>>> }
>>>>
>>>> /**
>>>> * Gets the id of this Article.
>>>> * @return the id
>>>> */
>>>> public Long getId()
>>>> {
>>>> return this.id;
>>>> }
>>>>
>>>> /**
>>>> * Sets the id of this Article to the specified value.
>>>> * @param id the new id
>>>> */
>>>> public void setId(Long id)
>>>> {
>>>> this.id = id;
>>>> }
>>>>
>>>> /**
>>>> * Returns a hash code value for the object. This implementation
>>>> computes * a hash code value based on the id fields in this object.
>>>> * @return a hash code value for this object.
>>>> */
>>>> @Override
>>>> public int hashCode()
>>>> {
>>>> int hash = 0;
>>>> hash += (this.getId() != null ? this.getId().hashCode() : 0);
>>>> return hash;
>>>> }
>>>>
>>>> /**
>>>> * Determines whether another object is equal to this Article.
>>>> The result is * <code>true</code> if and only if the argument is
>>>> not null and is a Article object that * has the same id field
>>>> values as this object.
>>>> * @param object the reference object with which to compare
>>>> * @return <code>true</code> if this object is the same as the
>>>> argument;
>>>> * <code>false</code> otherwise.
>>>> */
>>>> @Override
>>>> public boolean equals(Object object)
>>>> {
>>>> // TODO: Warning - this method won't work in the case the id
>>>> fields are not set
>>>> if (!(object instanceof Article)) {
>>>> return false;
>>>> }
>>>> Article other = (Article)object;
>>>> // If both are the same object, return true
>>>> if(this == other)
>>>> {
>>>> return true;
>>>> }
>>>> // If both objects have ids, compare their ids
>>>> if(this.getId() != null && other.getId() != null)
>>>> {
>>>> // If their ids are equal, return true
>>>> if(this.getId().equals(other.getId()))
>>>> {
>>>> return true;
>>>> }
>>>> // Otherwise, return false
>>>> else
>>>> {
>>>> return false;
>>>> }
>>>> }
>>>> // If one or both do not have ids, compare their 'natural keys'
>>>> if(this.getTitle() != null &&
>>>> this.getTitle().equals(other.getTitle())
>>>> && this.getCreatedDate() != null &&
>>>> this.getCreatedDate().equals(other.getCreatedDate())
>>>> && this.getPoster() != null &&
>>>> this.getPoster().equals(other.getPoster())
>>>> )
>>>> {
>>>> return true;
>>>> }
>>>> return false;
>>>> }
>>>>
>>>> /**
>>>> * Returns a string representation of the object. This
>>>> implementation constructs * that representation based on the id
>>>> fields.
>>>> * @return a string representation of the object.
>>>> */
>>>> @Override
>>>> public String toString()
>>>> {
>>>> return "com.acadept.model.Article[id=" + getId() + "]";
>>>> }
>>>>
>>>> public ArticleCategory getArticleCategory()
>>>> {
>>>> return articleCategory;
>>>> }
>>>>
>>>> public void setArticleCategory(ArticleCategory articleCategory)
>>>> {
>>>> this.articleCategory = articleCategory;
>>>> articleCategory.addArticle(this);
>>>> }
>>>>
>>>> public String getTitle()
>>>> {
>>>> return title;
>>>> }
>>>>
>>>> public void setTitle(String title)
>>>> {
>>>> this.title = title;
>>>> }
>>>>
>>>> public String getSubTitle()
>>>> {
>>>> return subTitle;
>>>> }
>>>>
>>>> public void setSubTitle(String subTitle)
>>>> {
>>>> this.subTitle = subTitle;
>>>> }
>>>>
>>>> public String getLeadIn()
>>>> {
>>>> return leadIn;
>>>> }
>>>>
>>>> public void setLeadIn(String leadIn)
>>>> {
>>>> this.leadIn = leadIn;
>>>> }
>>>>
>>>> public String getBody()
>>>> {
>>>> return body;
>>>> }
>>>>
>>>> public void setBody(String body)
>>>> {
>>>> this.body = body;
>>>> }
>>>>
>>>> public AppUser getPoster()
>>>> {
>>>> return poster;
>>>> }
>>>>
>>>> public void setPoster(AppUser poster)
>>>> {
>>>> this.poster = poster;
>>>> }
>>>>
>>>> public Date getCreatedDate()
>>>> {
>>>> return createdDate;
>>>> }
>>>>
>>>> public void setCreatedDate(Date createdDate)
>>>> {
>>>> this.createdDate = createdDate;
>>>> }
>>>>
>>>> public String getLeadInImage()
>>>> {
>>>> return leadInImage;
>>>> }
>>>>
>>>> public void setLeadInImage(String leadInImage)
>>>> {
>>>> this.leadInImage = leadInImage;
>>>> }
>>>>
>>>> public List<ArticlePlacement> getArticlePlacements()
>>>> {
>>>> return articlePlacements;
>>>> }
>>>>
>>>> public void setArticlePlacements(List<ArticlePlacement>
>>>> articlePlacements)
>>>> {
>>>> this.articlePlacements = articlePlacements;
>>>> }
>>>>
>>>> public void addArticlePlacement(ArticlePlacement articlePlacement)
>>>> {
>>>> if(this.getArticlePlacements().contains(articlePlacement))
>>>> {
>>>> return;
>>>> }
>>>> getArticlePlacements().add(articlePlacement);
>>>> articlePlacement.setArticle(this);
>>>> }
>>>>
>>>> public void removeArticlePlacement(ArticlePlacement articlePlacement)
>>>> {
>>>> getArticlePlacements().remove(articlePlacement);
>>>> articlePlacement.setArticle(null);
>>>> }
>>>>
>>>> @PreRemove
>>>> public void beforeRemove()
>>>> {
>>>> List<ArticlePlacement> articlePlacements = getArticlePlacements();
>>>> for(ArticlePlacement ap : articlePlacements)
>>>> {
>>>> ap.setArticle(null);
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>> /*
>>>> * ArticlePlacement.java
>>>> *
>>>> * Created on May 7, 2007, 2:32 PM
>>>> *
>>>> * To change this template, choose Tools | Template Manager
>>>> * and open the template in the editor.
>>>> */
>>>>
>>>> package com.acadept.model.article;
>>>>
>>>> import java.io.Serializable;
>>>> import java.util.Date;
>>>> import javax.persistence.Column;
>>>> import javax.persistence.Entity;
>>>> import javax.persistence.GeneratedValue;
>>>> import javax.persistence.GenerationType;
>>>> import javax.persistence.Id;
>>>> import javax.persistence.ManyToOne;
>>>> import javax.persistence.PreRemove;
>>>> import javax.persistence.SequenceGenerator;
>>>> import javax.persistence.Table;
>>>> import javax.persistence.Temporal;
>>>> import javax.persistence.TemporalType;
>>>>
>>>> /**
>>>> * Entity class ArticlePlacement
>>>> *
>>>> * @author gregederer
>>>> */
>>>> @Entity
>>>> @Table(name="article_placement")
>>>> public class ArticlePlacement implements Serializable
>>>> {
>>>> @Id
>>>> @GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
>>>> "ARTICLE_PLACEMENT_SEQ_GENERATOR")
>>>> @SequenceGenerator(name = "ARTICLE_PLACEMENT_SEQ_GENERATOR",
>>>> sequenceName = "ARTICLE_PLACEMENT_ID_SEQ")
>>>> private Long id;
>>>>
>>>> @ManyToOne
>>>> private Article article;
>>>>
>>>> @ManyToOne
>>>> private ArticleGroup articleGroup;
>>>>
>>>> @Temporal(value = TemporalType.TIMESTAMP)
>>>> @Column(name="order_position")
>>>> private Date position;
>>>>
>>>> @Temporal(TemporalType.TIMESTAMP)
>>>> private Date startRunDate;
>>>>
>>>> @Temporal(TemporalType.TIMESTAMP)
>>>> private Date endRunDate;
>>>>
>>>> /** Creates a new instance of ArticlePlacement */
>>>> public ArticlePlacement()
>>>> {
>>>> }
>>>>
>>>> /**
>>>> * Gets the id of this ArticlePlacement.
>>>> * @return the id
>>>> */
>>>> public Long getId()
>>>> {
>>>> return this.id;
>>>> }
>>>>
>>>> /**
>>>> * Sets the id of this ArticlePlacement to the specified value.
>>>> * @param id the new id
>>>> */
>>>> public void setId(Long id)
>>>> {
>>>> this.id = id;
>>>> }
>>>>
>>>> /**
>>>> * Returns a hash code value for the object. This implementation
>>>> computes
>>>> * a hash code value based on the id fields in this object.
>>>> * @return a hash code value for this object.
>>>> */
>>>> @Override
>>>> public int hashCode()
>>>> {
>>>> int hash = 0;
>>>> hash += (this.getId() != null ? this.getId().hashCode() : 0);
>>>> return hash;
>>>> }
>>>>
>>>> /**
>>>> * Determines whether another object is equal to this
>>>> ArticlePlacement. The result is
>>>> * <code>true</code> if and only if the argument is not null and
>>>> is a ArticlePlacement object that
>>>> * has the same id field values as this object.
>>>> * @param object the reference object with which to compare
>>>> * @return <code>true</code> if this object is the same as the
>>>> argument;
>>>> * <code>false</code> otherwise.
>>>> */
>>>> @Override
>>>> public boolean equals(Object object)
>>>> {
>>>> if (!(object instanceof ArticlePlacement))
>>>> {
>>>> return false;
>>>> }
>>>> ArticlePlacement other = (ArticlePlacement)object;
>>>> // If both are the same object, return true
>>>> if(this == other)
>>>> {
>>>> return true;
>>>> }
>>>> // If both objects have ids, compare their ids
>>>> if(this.getId() != null && other.getId() != null)
>>>> {
>>>> // If their ids are equal, return true
>>>> if(this.getId().equals(other.getId()))
>>>> {
>>>> return true;
>>>> }
>>>> // Otherwise, return false
>>>> else
>>>> {
>>>> return false;
>>>> }
>>>> }
>>>> // If one or both do not have ids, compare their 'natural keys'
>>>> if(this.getArticle() != null &&
>>>> this.getArticle().equals(other.getArticle())
>>>> && this.getArticleGroup() != null &&
>>>> this.getArticleGroup().equals(other.getArticleGroup())
>>>> )
>>>> {
>>>> return true;
>>>> }
>>>> return false;
>>>> }
>>>>
>>>> /**
>>>> * Returns a string representation of the object. This
>>>> implementation constructs
>>>> * that representation based on the id fields.
>>>> * @return a string representation of the object.
>>>> */
>>>> @Override
>>>> public String toString()
>>>> {
>>>> return "com.acadept.model.ArticlePlacement[id=" + getId() + "]";
>>>> }
>>>>
>>>> public Article getArticle()
>>>> {
>>>> return article;
>>>> }
>>>>
>>>> public void setArticle(Article article)
>>>> {
>>>> this.article = article;
>>>> if(article != null)
>>>> {
>>>> article.addArticlePlacement(this);
>>>> }
>>>> }
>>>>
>>>> public ArticleGroup getArticleGroup()
>>>> {
>>>> return articleGroup;
>>>> }
>>>>
>>>> public void setArticleGroup(ArticleGroup articleGroup)
>>>> {
>>>> this.articleGroup = articleGroup;
>>>> if(articleGroup != null)
>>>> {
>>>> articleGroup.addArticlePlacement(this);
>>>> }
>>>> }
>>>>
>>>> public Date getPosition()
>>>> {
>>>> return position;
>>>> }
>>>>
>>>> public void setPosition(Date position)
>>>> {
>>>> this.position = position;
>>>> }
>>>>
>>>> public Date getStartRunDate()
>>>> {
>>>> return startRunDate;
>>>> }
>>>>
>>>> public void setStartRunDate(Date startRunDate)
>>>> {
>>>> this.startRunDate = startRunDate;
>>>> }
>>>>
>>>> public Date getEndRunDate()
>>>> {
>>>> return endRunDate;
>>>> }
>>>>
>>>> public void setEndRunDate(Date endRunDate)
>>>> {
>>>> this.endRunDate = endRunDate;
>>>> }
>>>>
>>>> @PreRemove
>>>> public void beforeRemove()
>>>> {
>>>> getArticleGroup().removeArticlePlacement(this);
>>>> if(getArticle() != null)
>>>> {
>>>> getArticle().removeArticlePlacement(this);
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>> /*
>>>> * ArticleGroup.java
>>>> *
>>>> * Created on May 7, 2007, 2:27 PM
>>>> *
>>>> * To change this template, choose Tools | Template Manager
>>>> * and open the template in the editor.
>>>> */
>>>>
>>>> package com.acadept.model.article;
>>>>
>>>> import com.acadept.model.*;
>>>> import java.io.Serializable;
>>>> import java.util.ArrayList;
>>>> import java.util.List;
>>>> import java.util.logging.Logger;
>>>> import javax.persistence.CascadeType;
>>>> import javax.persistence.Column;
>>>> import javax.persistence.Entity;
>>>> import javax.persistence.GeneratedValue;
>>>> import javax.persistence.GenerationType;
>>>> import javax.persistence.Id;
>>>> import javax.persistence.OneToMany;
>>>> import javax.persistence.OrderBy;
>>>> import javax.persistence.SequenceGenerator;
>>>> import javax.persistence.Table;
>>>>
>>>> /**
>>>> * Entity class ArticleGroup
>>>> * * @author gregederer
>>>> */
>>>> @Entity
>>>> @Table(name="article_group")
>>>> public class ArticleGroup implements Serializable
>>>> {
>>>> private static Logger logger =
>>>> Logger.getLogger(ContentGroup.class.getName());
>>>>
>>>> @Id
>>>> @GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
>>>> "ARTICLE_GROUP_SEQ_GENERATOR")
>>>> @SequenceGenerator(name = "ARTICLE_GROUP_SEQ_GENERATOR",
>>>> sequenceName = "ARTICLE_GROUP_ID_SEQ")
>>>> private Long id;
>>>>
>>>> @Column(name="content_name", unique=true)
>>>> private String name;
>>>>
>>>> @Column(columnDefinition="text")
>>>> private String description;
>>>>
>>>> @OneToMany(cascade=CascadeType.ALL)
>>>> @OrderBy("position ASC")
>>>> private List<ArticlePlacement> articlePlacements = new
>>>> ArrayList<ArticlePlacement>();
>>>>
>>>> /**
>>>> * Gets the id of this ArticleGroup.
>>>> * @return the id
>>>> */
>>>> public Long getId()
>>>> {
>>>> return this.id;
>>>> }
>>>>
>>>> /**
>>>> * Sets the id of this ArticleGroup to the specified value.
>>>> * @param id the new id
>>>> */
>>>> public void setId(Long id)
>>>> {
>>>> this.id = id;
>>>> }
>>>>
>>>> /**
>>>> * Returns a hash code value for the object. This implementation
>>>> computes * a hash code value based on the id fields in this object.
>>>> * @return a hash code value for this object.
>>>> */
>>>> @Override
>>>> public int hashCode()
>>>> {
>>>> int hash = 0;
>>>> hash += (this.getId() != null ? this.getId().hashCode() : 0);
>>>> return hash;
>>>> }
>>>>
>>>> /**
>>>> * Determines whether another object is equal to this
>>>> ArticleGroup. The result is * <code>true</code> if and only if
>>>> the argument is not null and is a ArticleGroup object that * has
>>>> the same id field values as this object.
>>>> * @param object the reference object with which to compare
>>>> * @return <code>true</code> if this object is the same as the
>>>> argument;
>>>> * <code>false</code> otherwise.
>>>> */
>>>> @Override
>>>> public boolean equals(Object object)
>>>> {
>>>> // TODO: Warning - this method won't work in the case the id
>>>> fields are not set
>>>> if (!(object instanceof ArticleGroup)) {
>>>> return false;
>>>> }
>>>> ArticleGroup other = (ArticleGroup)object;
>>>> // If both are the same object, return true
>>>> if(this == other)
>>>> {
>>>> return true;
>>>> }
>>>> // If both objects have ids, compare their ids
>>>> if(this.getId() != null && other.getId() != null)
>>>> {
>>>> // If their ids are equal, return true
>>>> if(this.getId().equals(other.getId()))
>>>> {
>>>> return true;
>>>> }
>>>> // Otherwise, return false
>>>> else
>>>> {
>>>> return false;
>>>> }
>>>> }
>>>> // If one or both do not have ids, compare their 'natural keys'
>>>> if(this.getName() != null && this.getName().equals(other.getName())
>>>> )
>>>> {
>>>> return true;
>>>> }
>>>> return false;
>>>> }
>>>>
>>>> /**
>>>> * Returns a string representation of the object. This
>>>> implementation constructs * that representation based on the id
>>>> fields.
>>>> * @return a string representation of the object.
>>>> */
>>>> @Override
>>>> public String toString()
>>>> {
>>>> return "com.acadept.model.ArticleGroup[id=" + getId() + "]";
>>>> }
>>>>
>>>> public static Logger getLogger()
>>>> {
>>>> return logger;
>>>> }
>>>>
>>>> public static void setLogger(Logger aLogger)
>>>> {
>>>> logger = aLogger;
>>>> }
>>>>
>>>> public String getName()
>>>> {
>>>> return name;
>>>> }
>>>>
>>>> public void setName(String name)
>>>> {
>>>> this.name = name;
>>>> }
>>>>
>>>> public String getDescription()
>>>> {
>>>> return description;
>>>> }
>>>>
>>>> public void setDescription(String description)
>>>> {
>>>> this.description = description;
>>>> }
>>>>
>>>> public List<ArticlePlacement> getArticlePlacements()
>>>> {
>>>> return articlePlacements;
>>>> }
>>>>
>>>> public void setArticlePlacements(List<ArticlePlacement>
>>>> articlePlacements)
>>>> {
>>>> this.articlePlacements = articlePlacements;
>>>> }
>>>>
>>>> public void addArticlePlacement(ArticlePlacement articlePlacement)
>>>> {
>>>> if(this.getArticlePlacements().contains(articlePlacement))
>>>> {
>>>> return;
>>>> }
>>>> getArticlePlacements().add(articlePlacement);
>>>> articlePlacement.setArticleGroup(this);
>>>> }
>>>>
>>>> public void removeArticlePlacement(ArticlePlacement articlePlacement)
>>>> {
>>>> getArticlePlacements().remove(articlePlacement);
>>>> articlePlacement.setArticleGroup(null);
>>>> }
>>>> }
>>>>
>>>>
>>>>> Thanks,
>>>>>
>>>>> -- markus.
>>>>>
>>>>> Greg Ederer wrote:
>>>>>
>>>>>> Markus Fuchs wrote:
>>>>>>
>>>>>>> Hi Greg,
>>>>>>>
>>>>>>> Do you get a foreign key violation w/o using @PreRemove
>>>>>>> callbacks in your pojos? Are you using a current glassfish build?
>>>>>>>
>>>>>> Hi Markus,
>>>>>>
>>>>>> Yes. When I em.remove() an ArticlePlacement without the
>>>>>> @PreRemove, I get a PSQLException (I'm using PostgreSQL) with a
>>>>>> foreign key constraint violation message.
>>>>>>
>>>>>> I'm using v2b50.
>>>>>>
>>>>>> Thanks for the reply.
>>>>>>
>>>>>> Cheers,
>>>>>>
>>>>>> Greg
>>>>>>
>>>>>>> Thanks,
>>>>>>>
>>>>>>> -- markus.
>>>>>>>
>>>>>>> Greg Ederer wrote:
>>>>>>>
>>>>>>>> I managed to get this working by adding the following to Article:
>>>>>>>>
>>>>>>>> @PreRemove
>>>>>>>> public void beforeRemove()
>>>>>>>> {
>>>>>>>> List<ArticlePlacement> articlePlacements =
>>>>>>>> getArticlePlacements();
>>>>>>>> for(ArticlePlacement ap : articlePlacements)
>>>>>>>> {
>>>>>>>> ap.setArticle(null);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> And in ArticlePlacement:
>>>>>>>>
>>>>>>>> @PreRemove
>>>>>>>> public void beforeRemove()
>>>>>>>> {
>>>>>>>> getArticleGroup().removeArticlePlacement(this);
>>>>>>>> if(getArticle() != null)
>>>>>>>> {
>>>>>>>> getArticle().removeArticlePlacement(this);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> I have a feeling this is not the best way to handle this (and,
>>>>>>>> I'm guessing that I'll feel like a dummy when I find out the
>>>>>>>> correct way to do this, because it will be pretty obvious).
>>>>>>>>
>>>>>>>> Any advice welcome.
>>>>>>>>
>>>>>>>> Cheers,
>>>>>>>>
>>>>>>>> Greg
>>>>>>>>
>>>>>>>> Greg Ederer wrote:
>>>>>>>>
>>>>>>>>> Oops! Accidentally hit send. Please ignore previous post.
>>>>>>>>>
>>>>>>>>> I have a model containing three entity classes: Article,
>>>>>>>>> ArticleGroup and ArticlePlacement. An ArticleGroup contains
>>>>>>>>> zero or more ArticlePlacement objects. Each ArticlePlacement
>>>>>>>>> wraps an Article (ArticlePlacement also has a start run date
>>>>>>>>> and an end run date, which allows me to run an article in
>>>>>>>>> multiple groups during different periods).
>>>>>>>>>
>>>>>>>>> So, in Article, I have:
>>>>>>>>>
>>>>>>>>> @OneToMany(mappedBy = "article", cascade=CascadeType.ALL)
>>>>>>>>> private List<ArticlePlacement> articlePlacements = new
>>>>>>>>> ArrayList<ArticlePlacement>();
>>>>>>>>>
>>>>>>>>> In ArticleGroup, I have:
>>>>>>>>>
>>>>>>>>> @OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE,
>>>>>>>>> CascadeType.REFRESH})
>>>>>>>>> @OrderBy("position ASC")
>>>>>>>>> private List<ArticlePlacement> articlePlacements = new
>>>>>>>>> ArrayList<ArticlePlacement>();
>>>>>>>>>
>>>>>>>>> And, in ArticlePlacement, I have:
>>>>>>>>>
>>>>>>>>> @ManyToOne
>>>>>>>>> private Article article;
>>>>>>>>>
>>>>>>>>> @ManyToOne
>>>>>>>>> private ArticleGroup articleGroup;
>>>>>>>>>
>>>>>>>>> @PreRemove
>>>>>>>>> public void beforeRemove()
>>>>>>>>> {
>>>>>>>>> getArticleGroup().removeArticlePlacement(this);
>>>>>>>>> getArticle().removeArticlePlacement(this);
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> When I EntityManager.remove() an Article, I get a
>>>>>>>>> java.util.ConcurrentModificationException due to the
>>>>>>>>> getArticle().removeArticlePlacement(this) in @PreRemove,
>>>>>>>>> above. But, if I comment this out, I get a "violates foreign
>>>>>>>>> key" PSQLException.
>>>>>>>>>
>>>>>>>>> Can someone tell me how to deal with this situation correctly?
>>>>>>>>>
>>>>>>>>> Thanks!
>>>>>>>>>
>>>>>>>>> Greg
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>>
>>>>
>>>>
>>>
>>>


-- 
| E R G O N O S I S
| Greg Ederer
| Lead Developer
| greg_at_ergonosis.com
| 360.774.6848
|