【问题标题】:EclipseLink JPA Tracking ChangesEclipseLink JPA 跟踪更改
【发布时间】:2013-03-18 19:01:20
【问题描述】:

我尝试记录我的 JPA 实体的任何更改。出于这个原因,每个实体都继承自一个抽象实体类,该抽象实体类具有一个 LogEntry 对象列表。

AbstractEntity 类:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@EntityListeners(ChangeListener.class)
public abstract class AbstractEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Version
    private Long version;
    @Temporal(TemporalType.DATE)
    private Date validFrom;
    @Temporal(TemporalType.DATE)
    private Date validTo;
    private String name;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "abstractEntity")
    private List<LogEntry> logEntry = new ArrayList<LogEntry>();
    //getter and setter
}

LogEntry 类:

@Entity
public class LogEntry extends AbstractEntity {

    @ManyToOne
    @JoinColumn
    protected AbstractEntity abstractEntity;
    @ManyToOne
    @JoinColumn
    protected Person person; // creator or updater
    @Column(updatable=false, insertable=false, columnDefinition="TIMESTAMP DEFAULT   CURRENT_TIMESTAMP")
    @Temporal(TemporalType.TIMESTAMP)
    protected Date changeDate;
    protected String comment;
    //getter and setter
}

我的方法是创建一个新的 LogEntry 对象并将其添加到实体的 LogEntry 列表中,然后再更新或保留实体。

我尝试了以下解决方案:

  • 直接在实体类中使用回调注解(@PreUpdate、@PrePersist 等)或在与 AbstractEntity 连接的实体侦听器中分离
  • 在实体监听器中使用 EclipsLink 的 DescriptorEvent 和相应的回调方法。这是最有希望的试验。在 preUpdate 中,我可以向受影响的对象添加一个新的 LogEntry。添加的 LogEntry 甚至被正确地持久化了,但是 preUpdate 将被任何数据库操作调用(选择也会导致调用 preUpdate),所以我不能区分更改的对象和没有更改的对象。描述符事件、相关查询或 unitOfWork 提供的变更集在每种情况下都是空的。当前对象和旧对象的比较(由描述符事件提供)恕我直言太复杂了,不是吗? 另一方面,在 preUpdateWithChanges 中,我可以轻松检测到更改的实体,但此时添加日志条目显然为时已晚。日志条目不会被持久化。

几乎每个试验都使我能够更改受影响实体的属性(如名称或 validTo)。但是没有解决方案提供创建新 LogEntry 实例的机会,或者更确切地说是持久化这个 LogEntry 实例。我还尝试通过 jndi 查找获取会话 bean 的实例,以手动保存 LogEntry。 jndi 查找有效,但调用会话 bean 的创建或更新方法无效。

我当前的实体监听器如下所示:

public class ChangeListener extends DescriptorEventAdapter {

    @Override
    public void preUpdate(DescriptorEvent event) {
        AbstractEntity entity = (AbstractEntity) event.getObject();
        if (!(entity instanceof LogEntry)) {
            LogEntry logEntry = new LogEntry();
            logEntry.setPerson(getSessionController().getCurrentUser());
            logEntry.setAbstractEntity(entity);
            entity.getLogEntries().add(logEntry);
        }
    }
}

Hibernate Envers 由于各种原因没有选择。

EclipseLink 版本为 2.3.2。

【问题讨论】:

    标签: java jpa eclipselink audit changelog


    【解决方案1】:

    在提交过程中的事件期间持久化新对象可能很困难。

    您可以在提交之前获取更改并保留您的日志(从 UnitOfWork 获取更改集)。

    看, http://wiki.eclipse.org/EclipseLink/FAQ/JPA#How_to_access_what_changed_in_an_object_or_transaction.3F

    否则,可以直接从事件内部插入和对象。

    event.getSession().insertObject(logEntry);
    

    【讨论】:

    【解决方案2】:

    我暂时通过比较 preUpdate 中的当前实体和旧实体解决了这个问题。比较是使用来自Apache Commons LangEqualsBuilder 完成的。

    public class ChangeAbstractEntityListener extends DescriptorEventAdapter {
    
        @Override
        public void preUpdate(DescriptorEvent event) {
            AbstractEntity originalEntity = (AbstractEntity) event.getOriginalObject();
            AbstractEntity entity = (AbstractEntity) event.getObject();
    
            if (!EqualsBuilder.reflectionEquals(originalEntity, entity, true)) {
                if (!(entity instanceof LogEntry)) {
                    LogEntry logEntry = new LogEntry();
                    logEntry.setPerson(getSessionController().getCurrentUser());
                    logEntry.setAbstractEntity(entity);
                    entity.getLogEntries().add(logEntry);
                }
            }
        }
        //jndi lookup to get the user object
    }
    

    【讨论】:

      【解决方案3】:

      如果您想要简单的实体审计,那么看看 Hibernate 的 Envers 模块吧。

      它适用于 JPA(和 Spring-Data),并且可以存储每个更改的版本以及 如果您运行 Spring Security,则更改它。

      Envers 自 3.6 起成为 Hibernate 的一部分

      【讨论】:

        【解决方案4】:

        你可以试试Tracking Changes Using History Policy

        EclipseLink 为跟踪对数据库所做的所有更改提供了扩展支持。 EclipseLink HistoryPolicy 可以在 ClassDescriptor 上配置以存储原始镜像表,该镜像表将存储对象在任何时间点的状态。这可用于审计目的,或允许查询过去的时间点,或允许恢复旧数据。

        【讨论】:

          猜你喜欢
          • 2013-03-17
          • 1970-01-01
          • 2016-05-22
          • 1970-01-01
          • 2013-12-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多