How to just audit if a Set of Entities change i.e. adding further entities to this Set (NOT the entity itself) - hibernate-envers

Person is an auditable Entity and is already annotated with #Audited.
One of the property is a Set of Address and this Set is annotated with #OneToMany.
The Address itself is a not auditable entity.
If I ever have to change the Set of Addresses by adding a new address (not the Address entity itself), I have to Audit in an other table called person_aud_addresses.
The table person_aud_addresses should hold the added address_id and the revision of the person from person_aud.
#Entity
#Table(name = "person")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Audited
public class Person implements Serializable {
.....
#OneToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) //its not working because Address should not be auditable
private Set<Address> addresses = new HashSet<>();
.....
}
#Entity
#Table(name = "person_aud")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class PersonAud implements Serializable {
....
#OneToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Address> addresses = new HashSet<>();
....
}
#Entity
#Table(name = "address")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Address implements Serializable {
....
#ManyToOne
#JsonIgnoreProperties("addresses")
private Person person;
....
}

Related

Hibernate #OneToMany where discriminatorValue = 'SOMETHING'

Table pdp_billable_field_state carries configuration for various fields.
Owner of configuration can be any number of Entity`s
This configuration is same for each entity that matches the #DiscriminatorValue
#Getter
#Setter
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "entity_type")
#Table(name = "pdp_billable_field_state")
public abstract class EntityFieldStateJpa extends AuditableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "status_id")
private StatusJpa status;
#Column(name = "field", columnDefinition= "varchar(255)")
private String field;
private boolean disabled;
private boolean hidden;
}
#DiscriminatorValue("PURCHASE")
public class PurchaseEntityFieldStateJpa extends EntityFieldStateJpa {}
#Getter
#Setter
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "pdp_purchase")
public class PurchaseJpa {
// omitted
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
// i do not have a join_column since all records with entity_type PURCHASE map to all purchases, as these are configurations used by all purchases. Should i try and introduce #JoinTable maybe?
#Where(clause = "entity_type='PURCHASE'")
private List<PurchaseEntityFieldStateJpa> fieldStates;
}

JPA Criteria to query hierarchy of child objects

I have two tables that are represented by following entity object hierarchies:
#Entity
#Table(name = Transport.TABLE_NAME)
#DiscriminatorColumn(name="transport_type", discriminatorType = DiscriminatorType.INTEGER)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Transport {
...
private Date departure;
}
#Entity
#DiscriminatorValue("1")
public class Bicycle extends Transport {
...
#OneToOne(mappedBy = "transport", fetch = FetchType.LAZY)
private BikePassenger passenger;
}
#Entity
#DiscriminatorValue("2")
public class Car extends Transport {
...
#OneToMany(mappedBy = "transport", fetch = FetchType.EAGER)
private List<CarPassanger> passengers;
}
#Entity
#Table(name = Passenger.TABLE_NAME)
#DiscriminatorColumn(name="passenger_type", discriminatorType = DiscriminatorType.INTEGER)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Passenger {
...
private int passengerGUID;
}
#Entity
#DiscriminatorValue("1")
public class BicyclePassenger extends Passenger {
...
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "transportid")
private Bicycle transport;
}
#Entity
#DiscriminatorValue("2")
public class CarPassenger extends Passenger {
...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "transportid")
private Car transport;
}
Now using JPA Criteria API (or at least JPA) how do I:
Get all transports that have passengers with specific passengerGUID?
Group transports (along with passengers) by departure date?
As I see it #1 should have nice solution but I was able to get out only with 2 subselects for each subtype. Which looks ugly to me.
And finally third question - is it good model at all? From OOP point of view to me it looks ok, but from ORM point of view and easiness of queries it looks not so good...
p.s. I'm using hibernate JPA 2.1

one side set in many-to-many relation

I have three database tables: Customer, Product and PurchaseOrder (for mapping). I am using openjpa for peristence in java rest application.
To all of the tables I have corresponding entities:
Customer
#Entity
#Table(name = "customer")
#XmlRootElement
#NamedQueries({...})
public class Customer implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "customerId")
private Collection<PurchaseOrder> purchaseOrderCollection;
Product
#Entity
#Table(name = "product")
#XmlRootElement
#NamedQueries({...})
public class Product implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "productId")
private Collection<PurchaseOrder> purchaseOrderCollection;
PurchaseOrder
#Entity
#Table(name = "purchase_order")
#XmlRootElement
#NamedQueries({..})
public class PurchaseOrder implements Serializable {
...
#Id
#Basic(optional = false)
#Column(name = "order_num")
private Integer orderNum;
#JoinColumn(name = "customer_id", referencedColumnName = "customer_id")
#ManyToOne(optional = false)
private Customer customer;
#JoinColumn(name = "product_id", referencedColumnName = "product_id")
#ManyToOne(optional = false)
private Product product;
What is the best way to get all the customers who ordered a product with specific id?
I could create namedQuery, I could build criteria with joins etc. But i think there could be a better way how to make use of the mapping entity (what would be point of this entity otherway?). Something like setting the productId to the purchaseOrder entity and then fetch all the customers via purchaseOrderCollection in customer entity? But i cannot figure it out. Is there other way than custom/named query or criteria building?
Thanks.
ok I figured it out, it can be this way
long productId = //get the id
Product product = entityManager.find(Product.class, productId);
Collection<PurchaseOrder> purchaseOrderCollection = product.getPurchaseOrderCollection();
if (purchaseOrderCollection != null) {
List<Integer> customers = new ArrayList<>(product.getPurchaseOrderCollection().size());
for (PurchaseOrder purchaseOrder : product.getPurchaseOrderCollection()) {
customers.add(purchaseOrder.getCustomerId());
}
return customers;
} else {
return Collections.EMPTY_LIST; // or null;
}
feel free to offer better sollution :)

using #Embedabble with a foreign key and manyToMany relation

I wrote an example for the code i am trying to implement, i get an error with Constraint "Student_Teacher_FK" already exists.
the #embiddable class has a foreign key that is created twice with current code.
#Entity
public class Teacher {
#Id
#GeneratedValue
private Long id;
#Column(name = "Name")
private String name;
}
#Entity
public class Student{
#Id
#GeneratedValue
private Long id;
#Column(name = "Name")
private String name;
}
#Embeddable
public class StudentList implements Serializable {
#ManyToMany
#JoinTable(name = "Student_Teacher",
joinColumns =
#JoinColumn(name = "Student_ID", referencedColumnName = "ID"),
inverseJoinColumns =
#JoinColumn(name = "Teacher_ID", referencedColumnName = "ID")
)
#ForeignKey(name = "Student_Teacher_FK", inverseName = "Teacher_Student_FK")
public List<Student> studentList = new ArrayList<Student>();
}
#Entity
public class HistoryTeacher extends Teacher {
#Embedded
#NotNull
private StudentList StudentList = new StudentList ();
}
#Entity
public class LangTeacher extends Teacher {
#Embedded
#NotNull
private StudentList StudentList = new StudentList ();
}
#Entity
public class RetiredTeacher extends Teacher {
// has no students
}
#embeddable : Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity (http://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html)
As you are declaring it in 2 different entity, jpa will create associated association table (student-teacher) 2 times with associated fk, which is explicitely named, and so created 2 times too with the same name. Here is your error.
I don't think using #embeddable is appropriated for what you're intending to do. A student has is own existence and is not part of teacher itself (not an uml composition / black diamond) so it's not an embeddable entity. Student list should be held by teacher entity using a simple manyToMany association.

JPA/Hibernate inheritance while loading: IllegalArgumentException, try to set wrong subclass

I'm using JBoss 6.1, I have the a JPA entagled situation, as a result I got the following error message:
IllegalArgumentException: Can not set EquipmentB field EquipmentCycleB.equipment to EquipmentA
suppose that each entity has an #Id annotated field:
A first hierarchy
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DIS", discriminatorType = DiscriminatorType.STRING, length = 1)
public abstract class Equipment { ... }
#Entity
#DiscriminatorValue("A")
public class EquipmentA extends Equipment { ... }
#Entity
#DiscriminatorValue("B")
public class EquipmentB extends Equipment { ... }
A second hierarchy
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DIS", discriminatorType = DiscriminatorType.STRING, length = 10)
public abstract class EquipmentCycle {
...
}
#Entity
#DiscriminatorValue("A")
public class EquipmentCycleA extends EquipmentCycle {
#JoinColumn(name = "EQUIPMENT_ID", referencedColumnName = "ID")
#ManyToOne
private EquipmentA equipment;
...
}
#Entity
#DiscriminatorValue("B")
public class EquipmentCycleB extends EquipmentCycle {
#JoinColumn(name = "EQUIPMENT_ID", referencedColumnName = "ID")
#ManyToOne
private EquipmentB equipment;
...
}
So far nothing strange, go on, the class say Status
#Entity
public class State {
#JoinColumn(name = "ENTITY_ID", referencedColumnName = "ID", nullable = false)
#ManyToOne
private EnityWithState enityWithState;
#JoinColumn(name = "EQUIPMENT_ID", referencedColumnName = "ID")
#ManyToOne
private Equipment equipment;
#JoinColumn(name = "EQUIPMENT_CYCLE_ID", referencedColumnName = "ID")
#ManyToOne
private EquipmentCycle equipmentCycle;
...
}
and the class which the state belong to
public class EnityWithState {
...
#OneToMany(mappedBy = "enityWithState", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<State> stateHistory;
...
}
Don't ask me why, I have just found it.
After some time the DB store the following data
Table Equipment
ID DIS
--------------------------------
1 A ...
2 B ...
Table EquipmentCycle
ID DIS EQUIPMENT_ID
--------------------------------
1 A 1
2 B 2
Table State
ID ENTITY_ID EQUIPMENT_ID EQUIPMENT_CYCLE_ID
---------------------------------------------
1 1 1 1
2 1 2 2
And finally, when I try lo load the EnityWithState with id 1, I got the following error:
IllegalArgumentException: Can not set EquipmentB field EquipmentCycleB.equipment to EquipmentA
Does anyone have any idea? I googled but I found nothing.
Could it be an Hibernate/JPA bug?
Thanks in advance for the help