Hibernate Envers:-Addition of Object in Collection member variable also creates a entry in Audit Table of Main Class - hibernate-envers

There are 2 classes which are both audited.
#Entity
#Audited
#Table(name = "PLACE")
public class Place {
private long woeId;
private Set<PlaceName> placeNames;
#OneToMany(mappedBy = "place", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#Fetch(FetchMode.JOIN)
public Set<PlaceName> getPlaceNames() {
return placeNames;
}
....
}
#Entity
#Audited
#Table(name = "PLACE_NAME")
#Check(constraints = "NAME_TYPE in ('N', 'V', 'A', 'S', 'P', 'Q', 'A1', 'A2', 'A3', 'FA', 'FI', 'IA', 'IC', 'I2', 'I3', 'NA', 'P1', 'P2')")
#Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class PlaceName implements Serializable {
private long id;
private String name;
private Place place;
#Id
#SequenceGenerator(name = "SEQ_STORE", sequenceName = "PLACE_NAME_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STORE")
#Column(name = "NAME_ID", columnDefinition = "NUMBER(12, 0)", nullable = false)
public long getId() {
return id;
}
/**
* #param id
* the id to set
*/
public void setId(long id) {
this.id = id;
}
#Column(name = "NAME", columnDefinition = "NVARCHAR2(512)", nullable = false)
public String getName() {
return name;
}
/**
* #param name
* the name of the {#link Place}
*/
public void setName(String name) {
this.name = name;
}
/**
* #return the {#link Place} this name is associated with
*/
#ManyToOne
#JoinColumn(name = "WOE_ID")
public Place getPlace() {
return place;
}
/**
* #param place
* the {#link Place} this name is associated with
*/
public void setPlace(Place place) {
this.place = place;
}
}
So, when a place name is added in PLACE_NAME table using
Place place = session.get(Place.class, new Integer(1));
PlaceName pn = new PlaceName();
pn.setName("ABC");
pn.setPlace(place);
then, in PLACE_NAME_AUD table, a entry is inserted but also a entry is added in PLACE_AUD table? What is the reason of that?

That's because looking at Place, the collection changed. This is configurable via the org.hibernate.envers.revision_on_collection_change config property. See the docs for details.

Related

List object mapped as EAGER is being fetched as LAZY - migrating Spring + Hibernate from 4 to 5 throwing org.hibernate.LazyInitializationException

Spring version: 5.3.19
Hibernate: 5.4.24.Final
The problem: When trying to get the List compartments from class CriticalFlight after ScrollableData gets Cleaned up #Cleanup, the list is empty since fetch was never executed.
Custom class ScrollableData execution snipped code:
List<ENTITY> filteredEntities;
#Cleanup ScrollableData<ENTITY> scrollableData =
getScrollableData(
filter,
myMarketChecker,
additionalFilters,
staticPredicateBuilders);
filteredEntities = scrollableData.getAll();
return filteredEntities;
I loop into the list returned and try to access List compartments
then got: "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.pros.travel.services.oandd.optimizer.alerts.entity.CriticalFlight.compartments, could not initialize proxy - no Session
"
Classes
Embeddable Class: CriticalFlightKey
#Data
#Embeddable
public class CriticalFlightKey implements Serializable
{
#DTOMapping(CriticalFlightDTO.FIELD_FLIGHTDATE)
#Convert(converter = DateToLocalDateAttributeConverter.class)
#Column(name = "FLTDATE", nullable = false)
private LocalDate flightDate;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_CRRCODE)
#Column(name = "CRRCODE", nullable = false)
private String carrierCode;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_FLTNUM)
#Column(name = "FLTNUM", nullable = false)
private String flightNumber;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_ORGN)
#Column(name = "ORGN", nullable = false)
private String origin;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_DSTN)
#Column(name = "DSTN", nullable = false)
private String destination;
}
Parent Class: CriticalFlight
#Data
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "OD_CRITICAL_FLIGHTS")
public class CriticalFlight implements
{
#JsonUnwrapped
#EmbeddedId
#DTOMapped
public CriticalFlightKey id;
...
....
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#JoinColumns({
#JoinColumn(name="FLTDATE", referencedColumnName="FLTDATE"),
#JoinColumn(name="CRRCODE", referencedColumnName="CRRCODE"),
#JoinColumn(name="FLTNUM", referencedColumnName="FLTNUM"),
#JoinColumn(name="ORGN", referencedColumnName="ORGN"),
#JoinColumn(name="DSTN", referencedColumnName="DSTN")
})
private List<CriticalFlightCmp> compartments = new ArrayList<>();
}
Embeddable class for child: CriticalFlightCmpKey
#Data
#Embeddable
public class CriticalFlightCmpKey implements Serializable
{
#Convert(converter = DateToLocalDateAttributeConverter.class)
#Column(name = "FLTDATE", nullable = false)
private LocalDate flightDate;
#Column(name = "CRRCODE", nullable = false)
private String carrierCode;
#Column(name = "FLTNUM", nullable = false)
private String flightNumber;
#Column(name = "ORGN", nullable = false)
private String origin;
#Column(name = "DSTN", nullable = false)
private String destination;
#Column(name = "CMPCODE", nullable = false)
private String cmpCode;
}
Child Class: CriticalFlightCmp
#Data
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "OD_CRITICAL_FLIGHTS_CMP")
public class CriticalFlightCmp implements IPersistable<CriticalFlightCmpKey>
{
#EmbeddedId
private CriticalFlightCmpKey id;
..
...
}
Custom class ScrollableData which uses org.hibernate.ScrollableResults to execute the query
#Slf4j
public class ScrollableData<ENTITY extends IPersistable> implements Closeable
{
private static final int SCROLLABLE_FETCH_SIZE = 10000;
private final Class<ENTITY> entityClass;
private final ScrollableResults results;
private final EntityManager entityManager;
private final List<IScrollableFilter<ENTITY>> filters = new ArrayList<>();
public ScrollableData(
Class<ENTITY> entityClass,
ScrollableResults results,
EntityManager entityManager)
{
this.entityClass = entityClass;
this.results = results;
this.entityManager = entityManager;
}
/**
* Create scrollable data from a query and entity manager session.
*
* #param entityManager Entity manager from which the query was built from.
* #param query Query to scroll on.
* #return Scrollable data
*/
static <ENTITY extends IPersistable> ScrollableData<ENTITY> fromQuery(
Class<ENTITY> entityClass,
EntityManager entityManager,
CriteriaQuery query)
{
ScrollableResults results = entityManager.createQuery(query)
.unwrap(Query.class)
.setReadOnly(true)
.setFetchSize(SCROLLABLE_FETCH_SIZE)
.setCacheable(false)
.scroll(ScrollMode.FORWARD_ONLY);
return new ScrollableData<>(entityClass, results, entityManager);
}
public List<ENTITY> getAll()
{
List<ENTITY> allEntities = new ArrayList<>();
while (next())
{
allEntities.add(get());
}
return allEntities;
}
/**
* Clears the hibernate session of any entities it's caching.
*/
public void clearSession()
{
log.debug("Clearing Session for {}", entityClass.getSimpleName());
Session hibernateSession = entityManager.unwrap(Session.class);
hibernateSession.clear();
}
/**
* Closes the scrollable results and the session contained in the entity manager.
*/
public void close()
{
clearSession();
if (results != null)
{
log.debug("Closing ScrollableResults for {}",
entityClass.getSimpleName());
results.close();
}
if (entityManager != null)
{
log.debug("Clearing EntityManager for {}", entityClass.getSimpleName());
entityManager.close();
}
}
}

JPA many to many relation: unable to insert into generated table

I have 2 entities "Entree" and "Emplacement":
#Entity
#Table(name = "ENTREE")
public class Entree {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_ENTREE", updatable = false, nullable = false)
private long idEntree;
#Column(name = "NUM_DECLARATION", insertable=true, updatable=true, nullable=true)
private String numDeclaration;
#Column(name = "DATE_ENTREE", insertable=true, updatable=true, nullable=true)
private String dateEntree;
#Column(name = "TYPE_ENTREE", insertable=true, updatable=true, nullable=true)
private String typeEntree;
#Column(name = "NOM_ARTICLE", insertable=true, updatable=true, nullable=true)
private String nomArticle;
#Column(name = "TYPE_ARTICLE", insertable=true, updatable=true, nullable=true)
private String typeArticle;
#Column(name = "QUANTITE_ENTREE", insertable=true, updatable=true, nullable=true)
private int quantiteEntree;
#ManyToOne
#JoinColumn(name="idDossier", nullable=false)
private Dossier dossier;
#ManyToMany( fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "entree_emplacement",
joinColumns = {
#JoinColumn(name = "id_entree", referencedColumnName = "id_entree",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "id_emplacement", referencedColumnName = "id_emplacement",
nullable = false, updatable = false)})
private Set<Emplacement> emplacement = new HashSet<>();
public Entree() {
super();
}
public Entree( String numDeclaration, String dateEntree, String typeEntree, String nomArticle, String typeArticle, int quantiteEntree, boolean isDone) {
super();
this.numDeclaration = numDeclaration;
this.dateEntree = dateEntree;
this.typeEntree = typeEntree;
this.nomArticle = nomArticle;
this.typeArticle = typeArticle;
this.quantiteEntree = quantiteEntree;
}
public long getIdEntree() {
return idEntree;
}
public void setIdEntree(long idEntree) {
this.idEntree = idEntree;
}
public String getNumDeclaration() {
return numDeclaration;
}
public void setNumDeclaration(String numDeclaration) {
this.numDeclaration = numDeclaration;
}
public String getDateEntree() {
return dateEntree;
}
public void setDateEntree(String dateEntree) {
this.dateEntree = dateEntree;
}
public String getTypeEntree() {
return typeEntree;
}
public void setTypeEntree(String typeEntree) {
this.typeEntree = typeEntree;
}
public String getNomArticle() {
return nomArticle;
}
public void setNomArticle(String nomArticle) {
this.nomArticle = nomArticle;
}
public String getTypeArticle() {
return typeArticle;
}
public void setTypeArticle(String typeArticle) {
this.typeArticle = typeArticle;
}
public int getQuantiteEntree() {
return quantiteEntree;
}
public void setQuantiteEntree(int quantiteEntree) {
this.quantiteEntree = quantiteEntree;
}
public Dossier getDossier() {
return dossier;
}
public void setDossier(Dossier dossier) {
this.dossier = dossier;
}
public Set<Emplacement> getEmplacements() {
return emplacement;
}
public void addEmplacement(Emplacement emplacement) {
this.emplacement.add(emplacement);
emplacement.getEntrees().add(this);
}
public void removeEmplacement(Emplacement emplacement) {
this.emplacement.remove(emplacement);
emplacement.getEntrees().remove(this);
}
}
And here the second entity:
#Entity
#Table(name = "EMPLACEMENT")
public class Emplacement {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_EMPLACEMENT", updatable = false, nullable = false)
private long idEmplacement;
#Column(name = "NUM_EMPLACEMENT", insertable=true, updatable=true, nullable=false)
private String numEmplacement;
#ManyToMany(mappedBy = "emplacement", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
private Set<Entree> entree = new HashSet<>();
public Emplacement() {
}
public Emplacement( String numEmplacement) {
this.numEmplacement = numEmplacement;
}
public long getIdEmplacement() {
return idEmplacement;
}
public void setIdEmplacement(long idEmplacement) {
this.idEmplacement = idEmplacement;
}
public String getNumEmplacement() {
return numEmplacement;
}
public void setNumEmplacement(String numEmplacement) {
this.numEmplacement = numEmplacement;
}
public Set<Entree> getEntrees() {
return entree;
}
}
Here is my inserting code:
#PostMapping("/ajouterEntree")
public ResponseEntity<String> addEntree(#Valid Entree entree, BindingResult result,ModelMap modelMap, #RequestParam(name = "numDossier") String numDossier, #RequestParam(name = "emplacement") String liste_emplacements) {
Emplacement e = new Emplacement(liste_emplacements);
entree.getEmplacements().add(e);
entreeService.saveEntree(entree);
return new ResponseEntity<String>("ok" + result, HttpStatus.OK);
}
I am able to insert datas into Entree and Emplacement tables, but the third generated table named entree-emplacement is empty.
So how can I insert datas into generated table in #ManyToMany relation?
Thanks
Ok it's resolved. Here is my code:
if(!liste_emplacements.equals(""))
{
List<String> list = new ArrayList<String>(Arrays.asList(liste_emplacements.split(",")));
Emplacement[] emp = new Emplacement[list.size()];
for (int i=0; i<list.size() ;i++)
{
emp[i] = new Emplacement(Long.parseLong(list.get(i)));
entree.getEmplacements().add(emp[i]);
emp[i].getEntrees().add(entree);
}
}
entreeService.saveEntree(entree);
return new ResponseEntity<String>("ok" + result, HttpStatus.OK);

JPA- insert a ID of parent to child table

when there is a many to one associate between two object in hibernate(JPA) and we want insert a ID of parent to child table without new record in parent table how do I implement it?
#ManyToOne(targetEntity = RoleEntity.class,cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name = "FK_ROLE_ID",referencedColumnName = "ID")
private RoleEntity role;
I write this:
UserEntity userEntity=new UserEntity();
userEntity.setUserName(username);
userEntity.setPassword(password);
userEntity.setCreatedDate(new Date().toString());
RoleEntity roleEntity=new RoleEntity();
roleEntity.setTitle("user");
userEntity.setRole(roleEntity);
but the last three line also insert a new record in user table.
This completely of roleEntity:
package Entity;
import javax.persistence.*;
import java.io.Serializable;
/**
* Created by Mohsen on 7/10/2018.
*/
#Entity(name = "role")
#Table(name = "ROLE")
public class RoleEntity implements Serializable {
#Id
#Column(name = "ID")
#SequenceGenerator(name = "SEQ_ROLE", sequenceName = "SEQ_ROLE", allocationSize = 1)
#GeneratedValue(generator = "SEQ_ROLE", strategy = GenerationType.SEQUENCE)
private int id;
#Basic
#Column(name = "Title")
private String title;
// #OneToMany(targetEntity = UserEntity.class,cascade = CascadeType.ALL,fetch = FetchType.LAZY)
// #JoinColumn(name = "FK_ROLE_ID",referencedColumnName = "ID")
// private Set<UserEntity> user;
public RoleEntity() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
This completely of userEntity:
package Entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Mohsen on 7/10/2018.
*/
#Entity(name = "user")
#Table(name = "USERR")
public class UserEntity implements Serializable {
#Id
#Column(name = "ID")
#SequenceGenerator(name = "SEQ_USER", allocationSize = 1, sequenceName = "SEQ_USER")
#GeneratedValue(generator = "SEQ_USER", strategy = GenerationType.SEQUENCE)
private int id;
#Basic
#Column(name = "UserName", columnDefinition = "VARCHAR2(20 CHAR)")
private String userName;
#Basic
#Column(name = "Password", columnDefinition = "VARCHAR2(255 CHAR)")
private String password;
#Basic
#Column(name = "CreatedDate")
private String createdDate;
#Basic
#Column(name = "EndedDate")
private String endedDate;
#OneToOne(targetEntity = PeopleEntity.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private PeopleEntity people;
#ManyToOne(targetEntity = RoleEntity.class,cascade = CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name = "FK_ROLE_ID",referencedColumnName = "ID")
private RoleEntity role;
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
public UserEntity() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCreatedDate() {
return createdDate;
}
public void setCreatedDate(String createdDate) {
this.createdDate = createdDate;
}
public String getEndedDate() {
return endedDate;
}
public void setEndedDate(String endedDate) {
this.endedDate = endedDate;
}
public PeopleEntity getPeople() {
return people;
}
public void setPeople(PeopleEntity people) {
this.people = people;
}
}
I have found the solution
I set cascade = CascadeType.REMOVE in child object and it works

Error in a ManyToMany Relationship on Hibernate-JPA

I have a large DB on MySql Workbench and I'm trying to map the relationship between the entities on Eclipse Mars thanks to Hibernate and the JPA module. The fact is that I receive the error:
"In attribute 'personAddresses', the "mapped by" attribute 'peopleAdd' has an invalid mapping type for this relationship."
This are the entities involved.
1
I've to say that making a forward engineering, Hibernate creating for me an AddressId class, where the composite primary key of Address is mapped. I suspect that the problem could be this, but I'm not certain, can you help me please?
Under I post the code so that it's more clear to understand how the classes are implemented.
#Entity
#IdClass(AddressId.class)
#Table(schema = "YouDroop", name = "Address")
public class Address implements Serializable
{
...
private Collection<Person> peopleAdd = new HashSet<Person>();
#Id
#Column(name = "Address", length = 45, unique = true, nullable = false)
private String address;
#Id
#Column(name = "Number", unique = true, nullable = false)
private int number;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "PersonHasAddress",
joinColumns = {
#JoinColumn(name = "Address_Address", referencedColumnName = "Address", nullable = false),
#JoinColumn(name = "Address_Number", referencedColumnName = "Number", nullable = false)
},
inverseJoinColumns = {#JoinColumn(name = "Person_Email", referencedColumnName = "Email", nullable = false)}
)
public Collection<Person> getPeopleAddressed(){
return this.peopleAdd;
}
public void setPeopleAddressed(Collection<Person> people){
this.peopleAdd = people;
}
}
public class AddressId implements Serializable
{
private String address;
private int number;
public AddressId(){}
public AddressId(String address, int number) {
super();
this.address = address;
this.number = number;
}
...
}
#Entity
#Table(name = "Person", schema = "YouDroop", uniqueConstraints =
{ #UniqueConstraint(columnNames = "NickName"),
#UniqueConstraint(columnNames = "Password") })
public class Person implements Serializable
{
...
private Collection<Address> addresses = new HashSet<Address>();
...
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "peopleAdd")
public Collection<Address> getPersonAddresses(){
return this.addresses;
}
public void setPersonAddresses(Collection<Address> addresses){
this.addresses = addresses;
}
}
Since you placed you #ManyToMany annotation on your getter method (or property) and not on the field. The mappedBy attribute should reference the property instead and not the field.
#ManyToMany
public Collection<Person> getPeopleAddressed() {
...
}
So your mappedBy attribute should have been
#ManyToMany(mappedBy="peopleAddressed")
public Collection<Address> getPersonAddresses() {
...
}

Seeing "referencedColumnNames(ID) ... not mapped to a single property" error with a 1-M relationship after adding a composite key to the "1" side

I have an existing JPA entity ("Reference") with an ID column as its primary key that it inherits from a base class "BaseEntity" (using the #MappedSuperclass annotation on the superclass).
I also have a 1-M relationship between a Reference and another entity called Violation. Violation was previously defined with a foreign key "REFERENCE_ID" to the "ID" column of the Reference entity.
Recently, I tried to add an unrelated composite key to the Reference entity. This should not have affected the 1-M relationship between Reference and Violation. However, when I run the code in my tomcat server, I see the following stack trace:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(ID) of org.qcri.copydetection.sdk.metastore.entity.Violation.reference referencing org.qcri.copydetection.sdk.metastore.entity.Reference not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:205) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:110) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processEndOfQueue(AnnotationConfiguration.java:541) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processFkSecondPassInOrder(AnnotationConfiguration.java:523) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:380) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1459) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1086) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:685) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
... 39 common frames omitted
Here is the code for the 3 classes involved:
#Entity
#Table(name = "REFERENCE")
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
#IdClass(Reference.ContextualName.class)
public class Reference extends BaseEntity {
#Column(name= "LOCATION", unique=true)
#XmlElement
private String location;
#Id
#AttributeOverrides({
#AttributeOverride(name = "name", column = #Column(name = "NAME")),
#AttributeOverride(name = "account", column = #Column(name = "ACCOUNT_ID"))
})
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Reference() {}
public Reference(String name) {
setName(name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
#Embeddable
private class ContextualName implements Serializable {
private static final long serialVersionUID = -3687389984589209378L;
#Basic(optional = false)
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
ContextualName() {}
}
}
#MappedSuperclass
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
#XmlElement
private Long id;
#Basic(optional = true)
#Column(name = "CREATED", insertable = false, updatable = false, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
#Temporal(TemporalType.TIMESTAMP)
#XmlElement
private Date creationDate;
protected BaseEntity() {}
public Long getId() {
return id;
}
public void setId(Long id) {
if(this.id==null) {
this.id = id;
} else if (this.id!=id) {
throw new IllegalArgumentException("Cannot change the id after it has been set, as it is a generated field.");
}
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
if(this.creationDate==null) {
this.creationDate = creationDate;
} else if (this.creationDate!=creationDate) {
throw new IllegalArgumentException("Cannot change the creation-date after it has been set, as it is a generated field.");
}
}
}
#Entity
#Table(name = "VIOLATION")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Violation extends BaseEntity {
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "REFERENCE_ID", referencedColumnName = "ID")
private Reference reference;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "SUSPECT_ID", referencedColumnName = "ID")
private Suspect suspect;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#XmlTransient
#JoinColumn(name = "SEARCH_ID", referencedColumnName = "ID")
private Search search;
#Basic(optional = false)
#Column(name = "SCORE")
#XmlElement
private double score;
public Violation() {}
public Violation(Search search, Reference ref, Suspect sus, double score) {
this.search = search;
this.reference = ref;
this.suspect = sus;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Reference getReference() {
return reference;
}
public void setReference(Reference reference) {
this.reference = reference;
}
public Suspect getSuspect() {
return suspect;
}
public void setSuspect(Suspect suspect) {
this.suspect = suspect;
}
public Search getSearch() {
return search;
}
public void setSearch(Search search) {
if(this.search!=null && this.search!=search) {
this.search.removeViolation(this);
}
this.search = search;
if(search!=null) {
if(!search.getViolations().contains(this)) {
search.addViolation(this);
}
}
}
}
To cut a long story short, I'm totally confused how to go about adding a composite key to an existing (legacy) entity that already has an ID column. I can't remove the ID column, nor can I change the 1-M relationship between Reference and Violation. I can't for the life of me understand the error message because the "REFERENCE_ID" foreign key column of the Violation entity is being mapped to a single "ID" column of the Reference entity.
Many thanks in advance!