2017-09-27 8 views
0

で作業していない私は、単純なエンティティオブジェクトと履歴ポリシーEclipseLinkの歴史ポリシーは、MySQL生成されたIDの

@Entity 
@Customizer(MyHistoryPolicy.class) 
@Table(name = "employee") 
public class Employee { 
    @Id 
    @Column(name = "id") 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

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

    ... accessor methods 
} 


public class MyHistoryPolicy implements DescriptorCustomizer { 

    public void customize(ClassDescriptor descriptor) { 
     String historyTableName = descriptor.getTableName() + "_history"; 
     HistoryPolicy policy = new HistoryPolicy(); 
     policy.addHistoryTableName(historyTableName); 
     policy.addStartFieldName("start_date"); 
     policy.addEndFieldName("end_date"); 
     descriptor.setHistoryPolicy(policy); 
    } 
} 

新しいオブジェクトが正常に動作します挿入を持っています。オブジェクトを更新すると、idはゼロに設定されます。 Eclipselinkから次のデバッグログが表示されます

UPDATE employee SET name = ? WHERE (id = ?) 
    bind => [test name, 2] 
UPDATE employee_history SET end_date = ? WHERE ((end_date IS NULL) AND (id = ?)) 
    bind => [2017-09-27 17:45:25.316, 2] 
INSERT INTO employee_history (id, name, start_date) VALUES (?, ?, ?) 
    bind => [2, test name, 2017-09-27 17:45:25.316] 
SELECT LAST_INSERT_ID() 

ヒストリテーブルの挿入後に「SELECT LAST_INSERT_ID()」に注意してください。ヒストリテーブルには生成されたIDがないため、このクエリはゼロを返しています。この値はオブジェクトのidフィールドに上書きされています。元のIDは失われており、アプリケーションには問題があります。

誰かがEclipselinkでこの不足分をMySQLで克服する方法を知っていますか?

+0

これは[EclipseLinkの既知のバグ](https://bugs.eclipse.org/bugs/show_bug.cgi?id=323023)です。 2010年に報告されました! 7年後、私はこの固定[BuckleyとNunn](https://en.wikipedia.org/wiki/Buckley_%26_Nunn)を得る2つの可能性を持っていると思います。 – bludginozzie

答えて

0

誰かがこの質問に遭遇した場合に備えて、私のために働く回避策を開発しました。 JPAリスナーを使用して失われたIDを保存して復元するだけで簡単です。ここに私のコードはあります:

@MappedSuperclass 
public abstract class EclipseLinkHistoryFix { 

    @Transient 
    private Long savedId; 

    @Id 
    @Column(name = "id") 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 

    @PreUpdate 
    public void saveId() { 
     savedId = getId(); 
    } 

    @PostUpdate 
    public void restoreId() { 
     if (savedId != null) { 
      if (id == null || id.longValue() != savedId.longValue()) { 
       setId(savedId); 
      } 
      savedId = null; 
     } 
    } 

    public final Long getId() { 
     return id; 
    } 

    public final void setId(Long id) { 
     this.id = id; 
    } 
} 

このハックは、EclipseLinkの内部動作に依存するので、今後のアップデートでは機能しない可能性があります。 v2.6.4では幸いにも、PostUpdateコールバックは履歴が挿入された後に呼び出されるので、これはうまく動作します。