Define audit columns in base entity class when database column names differ? - java

I have a database with common audit columns in each table but with different column names.
e.g
The Person table has the following audit columns,
(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).
I am trying to map these using JPA annotations and use an event listener class to populate these audit columns automatically whenever they are persisted in the database.
I have a base abstract class containing these audit columns, I could then annotate this with #MappedSuperclass and put the entity listener annotation on here too. All neat and tidy, unfortunately the column names differ for each audited entity. I think the only option is to have the audit columns mapped separately on each entity?
Can anybody suggest a better method for doing this?
#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());
}
}

Thanks to Alan for the hint, by specifying column names on each object as below. This worked :)
#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{
}

Use the #Embeddable in combination with #MappedSuperClass:
First define the BaseDTO interface:
#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);
}
}
Then define the embeddable which will hold the audited fields.
User most common column names here.
#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;
}
}
Then you inject an embedded to each of the audited entities, overriding the column names where necessary:
#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;
}
}
Finally the listener can stay as you wrote it:
public class BaseDTOEventListener {
#PrePersist
public void onPreInsert(BaseDTO baseDTO){
baseDTO.setCreationUser("TEST");
baseDTO.setCreationDate(new Date());
}
}
Hope that helps.

You can use hibernate envers for the same purpose. You can annotate with #Audited. Apply #NotAudited to the entities you do not want to be
#Entity
#Table(name="PERSON")
#Audited
public class Person extends BaseDTO{
}
#Entity
#Audited
#Table(name="ADDRESS")
public class Address extends BaseDTO{
}

Related

Difficulty creating relationship with abstract class and embedded attribute with JPA/Hibernate

I'm trying, but have not been successful so far, using the following classes with Hibernate.
#MappedSuperclass
#Embeddable
public abstract class Foo {
// atributes...
}
#Embeddable
public class Poo extends Foo {
// atributes...
}
#Entity
#Table
public class None {
// atributes...
#Embedded
private Foo foo;
// constructor
public None(Foo foo) {
this.foo = foo;
}
}
// example of save
None none = new None(Poo poo);
save(none);
Hibernate returns: Cannot instantiate abstract class or interface
Is it possible to perform this operation with JPA?
I ran into the same problem.
It seems like #embedable does not work with #DiscriminatorColumn. The only way I could get this to work is to use #DiscriminatorColumn, but treat the #embedable like a separate entity on the same table.
What this means is that the query will likely join the table to itself.
#Entity
#Table(name="tbComputers")
public class Computer{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
public String motherboard;
#OneToOne
#JoinColumn(name="id")
public CPU cpu;
}
#Entity
#DiscriminatorColumn(name="cpu_type")
#Table(name="tbComputers")
public abstract class CPU {
#Id
private Long id;
#Column(name = "cpu")
public String name;
public abstract String someProcessorSpecificMethod();
}
#Entity
#DiscriminatorValue("Intel")
public class Intel extends CPU {
#Override
public String someProcessorSpecificMethod() {
return "Intel";
}
}
#Entity
#DiscriminatorValue("AMD")
public class AMD extends CPU {
#Override
public String someProcessorSpecificMethod() {
return "AMD";
}
}
EDIT: After further testing I found that while this works for reading data, it does not for persisting. It will create a separate INSERT. It seems like it is not supported https://hibernate.atlassian.net/browse/HHH-1910. The alternative is to to split the table.

Inheritance Hibernate/JPA multiple levels

I have problems with defining a schema with multiple level inheritance,
so in my case I have a schema like bellow :
Model(id,created)
UserModel extends Model (login,password)
CustomerModel extends UserModel (orders)
StoreOwnerModel extends UserModel (stores)
ProductModel extends Model(name,price)
I have set inheritance strategy in Model on TABLE_PER_CLASS, so that means that I want for each sub class of Model create a table.
and the inheritance strategy in UserModel is set to SINGLE_TABLE to have just one table for all UserModel's subClasses.
But in my data base I see that for each UserModel subclasses a table is generated.
and I can't find the DiscriminatorColumn user_type in the generated table table USERS corresponding to UserModel.
here are my entities:
Model.class
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
#MappedSuperclass
public abstract class Model {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer id;
#DateTimeFormat(pattern="dd/MM/yyyy hh:mm:ss")
private Date created;
//getters/setters
}
UserModel.class
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="user_type",discriminatorType=DiscriminatorType.STRING)
#SecondaryTable(name="USERS")
#DiscriminatorValue("user")
public class UserModel extends Model{
#Column(unique=true)
private String login;
//getters & setters
}
CustomerModel.class
#Entity
#DiscriminatorValue(value="customer")
public class CustomerModel extends UserModel{
private List<OrderModel> orders;
//getters & setters
}
StoreOwnerModel.class
#Entity
#DiscriminatorValue(value="store_owner")
public class StoreOwnerModel extends UserModel{
private List<StoreModel> stores;
//getters & setters
}
ProductModel.class
#Entity
public class StoreOwnerModel extends UserModel{
private String name;
private double price;
//getters & setters
}
PS: this is not a duplucated Question, I dont Find this Answer on any of previous ones.
according to #chris I should remove #Inheritance from Model entity
and I also removed #SecondaryTable(name="USERS") from UserModel and it worked just perfectly.

Loading of Properties from database in Hibernate?

I have three classes having class hierarchy as
ParentClass.java
having commons properties used for both ChildClass1 and ChildClass2.
ChildClass1 extends ParentClass
having properties used for this ChildClass1 + it also use some of the common properties from parent class
ChildClass2 extends ParentClass
having properties used for this ChildClass2 + it also use some of the common properties from parent class
This all properties are available into table with two columns
**Key value** Type
---------------------------------------
propertyKey1 propertyValue1 Child1
propertyKey2 propertyValue2 Child1
propertyKey3 propertyValue3 Child2
propertyKey4 propertyValue4 Child2
propertyKey5 propertyValue5 CommonPorperty
.. .. ..
propertyKeyn propertyValuen ..
Now I am not sure that how to load them from hibernate inheritance ?
Apology for silly question...
Thanks in advance
You need to put an additional column 'Discriminator' to inform Hibernate which instance should be loaded when you're working on same table with multiple types.
See example:
#Entity
#org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true)
#Table(name = "PARENT_TABLE")
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.INTEGER)
public abstract class ParentEntity implements java.io.Serializable {
private long id;
private String commonValue1;
#Id
#Column(name = "ID", nullable = false)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name = "Common_Value1")
public String getCommonValue1(){
return commonValue1;
}
public void setCommonValue1(String commonValue1){
this.commonValue1 = commonValue1;
}
}
#Entity
#DiscriminatorValue("1")
public class ChildEntity1 extends ParentEntity {
private String child1Value;
#Column(name = "Child1_Value")
public String getChild1Value(){
return child1Value;
}
public void setChild1Value(String child1Value){
this.child1Value = child1Value;
}
}
#Entity
#DiscriminatorValue("2")
public class ChildEntity2 extends ParentEntity {
private String child2Value;
#Column(name = "Child2_Value")
public String getChild2Value(){
return child2Value;
}
public void setChild2Value(String child2Value){
this.child2Value = child2Value;
}
}

Hibernate storing identifiers of another entities not whole entities?

I'm building RESTful service on java using JERSEY and need to implement relationships between entities storing just identifier on another entity not whole. Is there any way to implements it in the hibernate?
I'm using something like this but it is not working.
#Entity
#javax.persistence.Table(name = "manager_user")
public class ManagerUser extends User {
#ManyToOne(targetEntity = ShopAdminUser.class)
private Integer shopAdminUserId;
//...
}
#Entity
#javax.persistence.Table(name = "shop_admin_user")
public class ShopAdminUser extends User {
#Lob
private String contactData;
public String getContactData() {
return contactData;
}
public void setContactData(String contactData) {
this.contactData = contactData;
}
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class User {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
//...
}
It will be very comfortable for me to implement this.

Hibernate: override entity getter to add annotations

I need to override a getter of an entity object, on which the db column is defined, in it's superclass, so I can add additional annotations.
Example:
#MappedSuperclass
public class Person {
String name;
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}
Class Person contains common attributes for several entities. Class Employee extends person and defines a database table (table per class strategy). I also want to serialize class Employee to XML, so I need to add additional annotations to its getters, and therefore I'm overriding them.
The problem is that when I try to run this code, I get a Hibernate MappingException saying: Duplicate property mapping of name found in Employee.
Is there a way to tell Hibernate that the name getter in Employee is not duplicate but just overriden (perhaps with some annotation). Or is there another way to do what I need?
Try adding #Transient to the overriding property:
#Entity
#Table(name="employee")
#XmlType(name="employee")
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
#Transient
public String getName() {
return super.getName();
}
}
this is untested code but i hope it will work, use #AttributeOverride annotation like this
#Entity
#Table(name="employee")
#XmlType(name="employee")
#AttributeOverride(name = "name", column = #Column(name = "name"))
public class Employee extends Person {
#Override
#XmlAttribute(name = "name")
public String getName() {
return super.getName();
}
}

Categories