使用jpa更新多个实体2

时间:2013-07-07 08:00:08

标签: jpa merge java-ee-6 entitymanager updating

我需要帮助来了解ORM的工作原理。这是非常常见的场景。我有两个主表Organization和RelatedParty,它们必须是多对多的关系。但是还有relation_type属性定义了Organization和Relatedparty之间存在什么样的关系。

relational database entity model

这是我的实体类: 组织:

@Entity
@Table(name = "organization", catalog = "...", schema = "")
@XmlRootElement
public class Organization implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "organization_id", nullable = false)
    private Integer organizationId;
    @Column(name = "organization_name", nullable = false)
    private String organizationName;
    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "organization")
    private List<Organdrelatedparty> organdrelatedpartyList;
...
//getter setter methods

Organdrelatedparty:使用复合主键OrgandrelatedpartyPK

@Entity
@Table(name = "organdrelatedparty", catalog = "...", schema = "")
@XmlRootElement
public class Organdrelatedparty implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected OrgandrelatedpartyPK organdrelatedpartyPK;
    @JoinColumn(name = "relatedParty_id", referencedColumnName = "relatedParty_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, cascade= {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
    private Relatedparty relatedparty;
    @JoinColumn(name = "orgRelation_id", referencedColumnName = "orgRelation_id", nullable = false)
    @ManyToOne(optional = false)
    private ParOrgrelationtype orgRelationid;
    @JoinColumn(name = "organization_id", referencedColumnName = "organization_id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Organization organization;
...
//getter setter methods

OrgandrelatedpartyPK

@Embeddable
public class OrgandrelatedpartyPK implements Serializable {
    @Basic(optional = false)
    @NotNull
    @Column(name = "relatedParty_id", nullable = false)
    private int relatedPartyid;
    @Basic(optional = false)
    @NotNull
    @Column(name = "organization_id", nullable = false)
    private int organizationId;
...
//getter setter methods

RelatedParty:与organdRelatedParty类处于单向oneToMany关系。换句话说,relatedParty实体不知道另一方面的organdRelatedParty实体。

@Entity
@Table(name = "relatedparty", catalog = "...", schema = "")
@XmlRootElement
public class Relatedparty implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "relatedParty_id", nullable = false)
    private Integer relatedPartyid;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "firstName", nullable = false, length = 100)
    private String firstName;
    @Size(max = 100)
    @Column(name = "lastName", length = 100)
    private String lastName;
    @Basic(optional = false)
    @NotNull
    @Column(name = "isForeign", nullable = false)
    private boolean isForeign;
...
//getter setter methods

对于插入,如果我持久保存新的组织实体,它会将活动保持到新的OrgandrelatedParty,它也会将活动级联到新的RelatedParty。因此所有相关实体都是持久的,并且工作正常。

要进行更新,用户应更改现有组织和relatedParty实体,并将新的relatedParty添加到组织。因此,我们首先要删除所有OrgandrelatedParties,然后再添加新的relatedParties并再次编辑relatedParties。

这是我们处理更新的方法:我们将新组织以及所有新旧相关的部分作为列表传递给方法: 我们删除所有旧的OrgAndRelatedParties然后我们再次创建列表中的所有relatedParties作为新的OrgandrelatedParties。这是更新组织的主要方法。

 public void updateOrganization(Organization newOrganization, List<Relatedparty> newShareList) throws ControlException {
    try{
        tx.begin();
        this.updateOrgAndRelatedShares(newOrganization, newShareList);
        customerController.updateOrganization(newOrganization);
        tx.commit();
    }catch(ControlException ex){
...

customerController的updateOrganization方法首先通过实体管理器的find方法找到旧的Organization,然后将新组织的所有属性复制到old,然后合并旧组织并刷新:

public void updateOrganization(Organization newOrganization)
{
    Organization preOrganization = em.find(Organization.class, newOrganization.getOrganizationId);
    preOrganization.setOrganizationId(newOrganization.getOrganizationId);
    preOrganization.setOrganizationName(newOrganization.getOrganizationName);
    em.merge(preOrganization);
    em.flush();
}

这是其他方法:

@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void updateOrgAndRelatedShares(Organization org, List<Relatedparty> shareList)    throws ControlException
{   

    for(Iterator<Organdrelatedparty> it = org.getOrgandrelatedpartyList().iterator(); it.hasNext();)
    {   
        Organdrelatedparty op = it.next();
        it.remove();
        op.setOrganization(null);
        op.setRelatedparty(null);
        deleteOrgRelated(op);
    }
    org.getOrgandrelatedpartyList().clear();


    for(Relatedparty relatedParty: shareList){
        int parOrgRelationTypeId = relatedParty.getIsPerson() ? 1:2;
        createOrgAndRelatedParty(org, relatedParty, parOrgRelationTypeId);
    }

}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteOrgRelated(Organdrelatedparty org) throws ControlException{
    try{
    org = em.find(Organdrelatedparty.class, org.getOrgandrelatedpartyPK());
    em.remove(org);
    em.flush();
    }
    catch(Exception ex){
        Logger.getLogger(RelatedpartyController.class.getName()).log(Level.SEVERE, null, ex);
        throw new ControlException("Couln't delete org relation", ex);
    }
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void createOrgAndRelatedParty(Organization org, Relatedparty relatedParty,  int parOrgRelationTypeId) throws ControlException{
    if(findRelatedPartyByRegNum(relatedParty.getRegisterNumber()) == null || relatedParty.getRelatedPartyid() == null){
       createRelated(relatedParty);
    }else{
       relatedParty = updateRelatedParty(relatedParty);
    }
        Organdrelatedparty preOrp = new  Organdrelatedparty(relatedParty.getRelatedPartyid(), 
        preOrp.setOrganization(org);
        preOrp.setRelatedparty(relatedParty);
        preOrp.setOrgRelationid(prepareOrgandRelatedPartyType(parOrgRelationTypeId));
        org.getOrgandrelatedpartyList().add(preOrp);
    }

我的问题是当我将组织实体与新的List organdrelatedpartyList合并时 它抛出这样的异常:

SEVERE: java.lang.IllegalArgumentException: Cannot merge an entity that has been removed: mn.bsoft.crasmonclient.model.Organdrelatedparty[ organdrelatedpartyPK=mn.bsoft.crasmonclient.model.OrgandrelatedpartyPK[ relatedPartyid=71, organizationId=19 ] ]

我发现eclipseLink会先保留操作然后删除操作。所以我认为它试图插入具有相同复合id的organdrelatedparty实体与之前未从数据库中删除的实体。每次我删除旧的organdrelatedparties时我都会刷新。但它没有帮助。解决办法是什么?任何想法的人。

我正在使用jpa 2.0; eclipseLink作为提供者和glassfish 3.1.2

1 个答案:

答案 0 :(得分:0)

你似乎使这些变得比他们需要的要复杂得多。

为什么不直接删除已删除的Organdrelatedparty,而不是删除所有这些,然后再转发其中的一些?重新生成对象,尤其是在同一事务中,通常是一个坏主意。

正在发生的错误是在merge()上根据你所包含的代码你只在updateOrgAndRelatedShares()中调用merge,所以我看不到这个对象在这一点上是如何被删除的?或者您的代码与您显示的代码不同,请包含异常堆栈。

您的updateOrganization()方法很糟糕,它会更新对象ID,您永远不应该这样做。它也无缘无故地调用merge,它已经改变了对象。

此外,我通常建议使用IdClass而不是EmbeddedId,如果是IDENTITY,建议使用TABLE或SEQUENCE id生成。