当数据库列名称不同时,在基实体类中定义审计列?
Posted
技术标签:
【中文标题】当数据库列名称不同时,在基实体类中定义审计列?【英文标题】:Define audit columns in base entity class when database column names differ? 【发布时间】:2017-01-18 13:12:07 【问题描述】:我有一个数据库,每个表中都有公共审计列,但列名不同。
例如 Person 表有以下审计列,
(per_creation_user, per_creation_date, per_update_user, per_update_date), and the address table has audit columns called (add_creation_user, add_creation_date, add_update_user, add_update_date).
我正在尝试使用 JPA 注释映射这些,并使用事件侦听器类来自动填充这些审计列,只要它们持久存在于数据库中。
我有一个包含这些审计列的基本抽象类,然后我可以用@MappedSuperclass
对其进行注释,并将实体侦听器注释也放在此处。所有的整洁,不幸的是,每个审计实体的列名都不同。我认为唯一的选择是在每个实体上分别映射审计列?
有人可以提出更好的方法吗?
@EntityListeners(BaseDTOEventListener.class)
@MappedSuperclass
public abstract class BaseDTO
private String creationUser;
private Date creationDate;
@Entity
@Table(name="PERSON")
public class Person extends BaseDTO
@Entity
@Table(name="ADDRESS")
public class Address extends BaseDTO
public class BaseDTOEventListener
@PrePersist
public void onPreInsert(BaseDTO baseDTO)
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
【问题讨论】:
您可以使用属性覆盖重新定义从映射超类docs.oracle.com/javaee/6/api/javax/persistence/…扩展的类中的列 【参考方案1】:将@Embeddable
与@MappedSuperClass
结合使用:
首先定义BaseDTO
接口:
@EntityListeners(BaseDTOEventListener.class)
@MappedSuperclass
public abstract class BaseDTO
public abstract getAuditEmbeddable();
public void setCreationDate(Date date)
getAuditEmbeddable().setCreationDate(date);
public void setCreationUser(String user)
getAuditEmbeddable().setCreationUser(user);
然后定义将保存审计字段的嵌入。 此处为用户最常用的列名。
@Embeddable
public class AuditEmbeddable
@Column(name = "creationUser")
private String creationUser;
@Column(name = "creationDate")
private Date creationDate;
public String getCreationUser()
return creationUser;
public void setCreationUser(String creationUser)
this.creationUser = creationUser;
public Date getCreationDate()
return creationDate;
public void setCreationDate(Date creationDate)
this.creationDate = creationDate;
然后您向每个被审计实体注入嵌入,在必要时覆盖列名:
@Entity
@Table(name="PERSON")
public class Person extends BaseDTO
@Embedded
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable()
return auditEmbeddable;
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable)
this.auditEmbeddable = auditEmbeddable;
@Entity
@Table(name="ADDRESS")
public class Address extends BaseDTO
// lets say here you have custom names for audit fields
@Embedded
@AttributeOverrides(
@AttributeOverride(name = "creationUser", column = @Column(name = "creationUser123")),
@AttributeOverride(name = "creationDate", column = @Column(name = "creationDate123"))
)
private AuditEmbeddable auditEmbeddable;
public AuditEmbeddable getAuditEmbeddable()
return auditEmbeddable;
public void setAuditEmbeddable(AuditEmbeddable auditEmbeddable)
this.auditEmbeddable = auditEmbeddable;
最后听者可以保持你写的那样:
public class BaseDTOEventListener
@PrePersist
public void onPreInsert(BaseDTO baseDTO)
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
希望对您有所帮助。
【讨论】:
谢谢你,我最终按照艾伦·海伊在他的评论中逃避的方式去做了。我将在下面的答案中记录这一点。它与此非常相似,但不需要使用可嵌入对象。我注意到这两种解决方案可能存在的唯一问题是,如果有人在未指定要覆盖的属性的情况下扩展基类,如果持久化,它会创建与类属性同名的列。 您在 Embeddable 中定义默认列名。它们将在缺少覆盖的情况下使用。 问题是没有默认的审计列名,它们都有预先修复,但是可能通过定义一些默认的列名,这会抛出异常而不是休眠改变表,然后额外的表可以遵循此命名约定。 正确,我想你能在那个场景中做到最好。【参考方案2】:您可以将休眠环境用于相同目的。您可以使用@Audited 进行注释。将@NotAudited 应用于您不想成为的实体
@Entity
@Table(name="PERSON")
@Audited
public class Person extends BaseDTO
@Entity
@Audited
@Table(name="ADDRESS")
public class Address extends BaseDTO
【讨论】:
【参考方案3】:感谢 Alan 的提示,通过在每个对象上指定列名,如下所示。这工作:)
@Entity
@AttributeOverrides(@AttributeOverride(name="creationUser", column=@Column(name="PER_CREATION_USER", insertable=true, updatable=false)),
@AttributeOverride(name="creationDate", column=@Column(name="PER_CREATION_DATE" insertable=true, updatable=false)
@Table(name="PERSON")
public class Person extends BaseDTO
【讨论】:
以上是关于当数据库列名称不同时,在基实体类中定义审计列?的主要内容,如果未能解决你的问题,请参考以下文章