0

ORM の仕組みを理解するのに助けが必要です。これは非常に一般的なシナリオです。多対多の関係にある必要がある2つのメインテーブルOrganizationとRelatedPartyがあります。しかし、Organization と Relatedparty の間にどのような関係が存在するかを定義する relationship_type 属性もあります。

リレーショナル データベース エンティティ モデル

ここに私のエンティティクラスがあります: 組織:

@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

Organrelatedparty: 複合主キー 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

挿入の場合、新しい組織エンティティを永続化すると、永続化アクティビティが新しい OrganrelatedParty にカスケードされ、永続化アクティビティも新しい RelatedParty にカスケードされます。したがって、関連するすべてのエンティティが永続化され、正常に機能します。

更新の場合、ユーザーは既存の組織と関連当事者エンティティを変更し、新しい関連当事者を組織に追加する必要があります。そのため、最初にすべての 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);
    }

私の質問は、組織エンティティを新しいリスト 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 エンティティを挿入しようとしていると思います。古いオルガン関係者を外すたびにフラッシュします。しかし、それは役に立ちません。解決策は何ですか?どんなアイデアでも。

私はjpa 2.0を使用しています。プロバイダーとしての eclipseLink および glassfish 3.1.2

4

1 に答える 1

0

これらを必要以上に複雑にしているようです。

全部削除して一部を転生させるのではなく、削除された機関関係者だけ削除してはどうですか?特に同じトランザクション内でのオブジェクトの生まれ変わりは、通常は悪い考えです。

含まれているコードによると、発生しているエラーはmerge()にあります。 updateOrgAndRelatedShares()でのみmergeを呼び出すため、この時点でこのオブジェクトがどのように削除されるかわかりませんか? または、コードが表示と異なる場合は、例外スタックを含めてください。

updateOrganization() メソッドは不適切です。オブジェクト ID を更新しますが、これは絶対に行ってはいけません。また、理由もなくマージを呼び出します。オブジェクトは既に変更されています。

また、通常、EmbeddedId の代わりに IdClass を使用することをお勧めします。IDENTITY の場合は、代わりに TABLE または SEQUENCE ID 生成を使用することをお勧めします。

于 2013-07-08T13:42:54.253 に答える