4

私は EclipseLink 2.4.1 と JPA 2.0 を使用しています。私の例では、次のクラス定義があります。

@Entity
public class Shepard {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;


    @OneToMany(mappedBy = "shepard", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Sheep> sheeps;

    public void addSheep(Sheep sheep) {
        if (sheep != null) {
            if (sheeps == null) {
                sheeps = new ArrayList<>();
            }

            if (!sheeps.contains(sheep)) {
                sheeps.add(sheep);
            }
        }
    }
}

@Entity
public class Sheep {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name="shepard_id")
    private Shepard shepard;

    public Sheep(Shepard shepard, String name) {
        this.shepard = shepard;
        this.name = name;

        shepard.addSheep(this);
    }
}

ここで、Junit テストを作成して次のことを行います。Sheep コンストラクターが Shepard.addSheep(Sheep) を呼び出すことに注意してください。

EntityManagerFactory emf = Persistence.createEntityManagerFactory("data");
EnttyManager em = emf.createEntityManager();
Shepard shepard = new Shepard();

// I Persist Shepard
em.getTransaction().begin();
em.persist(shepard);
em.getTransaction().commit();

// II Persist Tilda
Sheep tilda = new Sheep(shepard, "Tilda");
em.getTransaction().begin();
em.persist(tilda);
em.getTransaction().commit();

// III Persist Martha via Shepard
Sheep martha = new Sheep(shepard, "Martha");
em.getTransaction().begin();
em.merge(shepard);
em.getTransaction().commit();

次に、羊の名前付きクエリを実行すると、"Tilda" のエントリが重複して取得されます。

コーディングすると、これは発生しません

em.persist(martha);

代わりに、最後のエンティティ マネージャ アクセスとして。

デバッグ出力を分析すると、IIの後に [id=1] を持つ 1 つの Shepard オブジェクトと [id=1] を持つ 1 つの Sheep オブジェクトがあることがわかります。IIIの前後で、Shepard は Sheeps の 2 つの参照を保持します。前に、Tilda の [id= 1 ] と Martha の [id=null] があります。IIIの後、Shepard は Tilda の [id= 2 ] と Martha の [id=3] を持つ Sheeps の 2 つの参照を保持します。

EclipseLink のデバッグ出力から、 IIIが Sheep テーブルに2 つの挿入ステートメントを発行していることがわかります。データベースには、上記の ID を持つ3 つのSheep エントリがあります。

さらに、次のエラーが表示されます。

[EL Warning]: 2013-06-21 09:53:26.631--UnitOfWork(221387686)--Thread(Thread[main,5,main])--Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [Sheep] is mapped to a primary key column in the database. Updates are not allowed.

これは EclipseLink のバグですか? または、ここで何が間違っていますか?

4

2 に答える 2

2

シェパードはすでに管理対象オブジェクトであるため、merge() を呼び出す必要はありません。Merge は、管理対象オブジェクトではなく、切り離された/シリアル化されたオブジェクト用です。カスケードが Sheep に永続化されている場合は、何もする必要はありません。commit を呼び出すだけです。

ただし、me​​rge() を呼び出しても問題は発生しないはずなので、これは非常に奇妙です。テストで問題を再現できる場合は、バグを記録してください。2.5 リリースを試して、修正されているかどうかを確認することもできます。

私の推測では、OneToMany EAGER を作成すると問題が解決する可能性があります。また、トランザクションごとに新しい EntityManager を作成すると、問題は発生しません (両方のケースでマージを呼び出す場合)。

于 2013-06-24T13:48:21.250 に答える