2017-09-27 39 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丢失,这对应用程序有问题。

有没有人知道如何克服与Eclipselink与MySQL的这种短缺?

+0

这是[EclipseLink中的已知错误](https://bugs.eclipse.org/bugs/show_bug.cgi?id=323023)。在2010年报道! 7年过去了,我想我有2次得到这个固定的机会[Buckley's和Nunn](https://en.wikipedia.org/wiki/Buckley_%26_Nunn)。 – 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的内部行为,因此可能无法在将来的更新。幸运的是,在2.6.6版本中,在插入历史记录之后调用PostUpdate回调函数,所以这很有用。