0

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

关系数据库实体模型

这是我的实体类: 组织:

@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

器官相关方PK

@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,这也将持久化活动级联到新的相关方。所以所有相关实体都被持久化并且工作正常。

对于更新,用户应更改现有组织和相关方实体,并将新的相关方添加到组织中。所以我们更愿意先删除所有的 OrgandrelatedParties,然后再添加新的 relatedParties 和编辑的 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 方法找到旧组织,然后将新组织的所有属性复制到旧组织,然后合并旧组织并刷新:

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);
    }

我的问题是,当我将组织实体与新的 ListorgandrelatedpartyList 合并时,它会抛出如下异常:

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 实体与之前未从数据库中删除的实体。每次我删除旧的器官相关方时,我都会脸红。但这无济于事。解决办法是什么?任何想法的家伙。

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

4

1 回答 1

0

You seem to be making these a lot more complicated than they need to be.

Why don't you just remove the Organdrelatedparty that have been removed, instead of deleting all of them, then reincarnating some of them? Reincarnating objects, especially in the same transaction is normally a bad idea.

The error that is occurring is on merge() according to the code you included you are only call merge in updateOrgAndRelatedShares(), so I don't see how this object is removed at this point? Or is your code different than you show, please include the exception stack.

You updateOrganization() method is bad, it updates the objects Id, which you should never do. Also it calls merge for no reason, it already changed the object.

Also I would normally recommend using an IdClass instead of an EmbeddedId, and recommend using TABLE or SEQUENCE id generation instead if IDENTITY.

于 2013-07-08T13:42:54.253 回答