Many-to-many relationship with composite keys, extra column in Hibernate - java

I have 3 data table:
Applications {id_app, version, name}
Customers {org_id, name}
Associations {id_app, version, org_id, state}.
Applications has a composite primary key (id_app, version), the primary key for Customers is org_id and Associations has a composite primary key (id_app, version, org_id).
In my java application I have the following classes:
#Entity
#Table(name = "Applications")
#IdClass(ApplicationId.class)
public class Application implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID_APP", nullable = false)
private String idApp;
#Id
#Column(name = "VERSION", nullable = false)
private String version;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy = "idPk.appPk", fetch = FetchType.LAZY) // cascade = CascadeType.ALL)
private List<Association> custApps;
// getters and setters
}
public class ApplicationId implements Serializable {
private static final long serialVersionUID = 1L;
private String idApp;
private String version;
//hashcode and equals
}
#Entity
#Table(name = "CUSTOMERS")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ORG_ID", unique = true, nullable = false)
private Integer orgID;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy="idPk.customerPk", fetch = FetchType.LAZY)
private List<Association> custApps;
//getters and setters
}
#Entity
#Table(name = "ASSOCIATIONS")
#AssociationOverrides({
#AssociationOverride(name = "idPk.appPk", joinColumns = #JoinColumn(name = "ID_APP")),
#AssociationOverride(name = "idPk.appPk", joinColumns = #JoinColumn(name = "VERSION")),
#AssociationOverride(name = "idPK.customerPk", joinColumns = #JoinColumn(name = "ORG_ID"))
})
public class Association implements Serializable {
private static final long serialVersionUID = 1L;
private AssociationId idPk = new AssociationId();
private String state;
public Association() {
super();
}
#EmbeddedId
public AssociationId getIdPk() {
return idPk;
}
#Transient
public Customer getCustomerPk() {
return idPk.getCustomerPk();
}
#Transient
public Application getAppPk() {
return idPk.getAppPk();
}
#Column(name = "STATE")
public String getState() {
return state;
}
//setters , hashCode and equals
}
#Embeddable
public class AssociationId implements Serializable {
private static final long serialVersionUID = 1L;
private Application appPk;
private Customer customerPk;
// here is the problem ?
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({ #JoinColumn(name = "ID_APP", referencedColumnName = "ID_APP"),
#JoinColumn(name = "VERSION", referencedColumnName = "VERSION") })
public Application getAppPk() {
return appPk;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="ORG_ID")
public Customer getCustomerPk() {
return customerPk;
}
//setter, hashCode and equals
}
What are the correct annotation? The relationship is many to many between Application and Customers and I create the Association table for that and for the extra column "state".
Now I receive this error: A Foreign key refering sla.model.Application from sla.model.Association has the wrong number of column. should be 2 .
Please help.

Done. I change the following:
In Association class:
#AssociationOverrides({
#AssociationOverride(name = "idPk.appPk", joinColumns = { #JoinColumn(name = "ID_APP", referencedColumnName = "ID_APP"),
#JoinColumn(name = "VERSION", referencedColumnName = "VERSION") }),
#AssociationOverride(name = "idPK.customerPk", joinColumns = #JoinColumn(name = "ORG_ID"))
})

Related

JPA: Access an object from another object returns null

I would like, from a key, to access the entity key above
The relationship is:
Rule contains a TermRule.
Each TermRule contains a rule and a variableConfiguration.
Only VariableConfiguration contains a Variable.
I would like, from TermRule, capture Variable.
I'm trying like this:
termRule.getVariableConfiguration().getVariable() and receiving null.
Its possible obtain the variable of a term?
public class Rule extends PersistentObject {
private static final long serialVersionUID = 7852189080136935020L;
#Column (name ="NAME", nullable = false)
private String namerule;
#OneToMany(mappedBy = "rule", fetch = FetchType.LAZY)
private List<TermRule> termRule;
}
//getters and setters
public class TermRule extends PersistentObject implements Comparable<TermRule> {
private static final long serialVersionUID = 336244667983772321L;
#ManyToOne
#JoinColumn(name = "ID_RULE", referencedColumnName = "ID", nullable = false)
private Rule rule;
#OneToOne
#JoinColumn (name ="ID_VAR_CONF", referencedColumnName = "ID", nullable = true)
private VariableConfiguration variableConfiguration;
}
public abstract class VariableConfiguration extends PersistentObject {
private static final long serialVersionUID = -4967631633375881594L;
#ManyToOne
#JoinColumn(name = "ID_VARIAVEL", referencedColumnName = "ID", nullable = false)
private Variable variable;
#OneToOne (mappedBy= "variableConfiguration", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private TermRule termRule;
}
#DiscriminatorValue("Triangle")
public class Triangle extends VariableConfiguration {
}
public class Variable extends PersistentObject {
private static final long serialVersionUID = -1172539974105845401L;
#Column (name = "NOME", nullable = false)
private String name;
#OneToMany (mappedBy= "variable", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<VariableConfiguration> variableConfiguration;
}

Prevent duplicate entries when saving Json with Nested Array of Objecs using Spring data Hibernate

I have a rest api that accept POST to save Candidates.
This the Object coming from POST:
{
"name": "renato",
"email":"rena#gmail.com",
"github":"renato.github.com",
"languages":[{"name":"Java"}],
"frameworks":[{"name":"Spring"}],
"linkedin":"renato.linkedin.com",
"motto":"the best",
"password":"1234"
}
then I do a Call to persist:
#Transactional
#Override
public boolean addCandidate(Candidate candidate) {
if (candidateRepository.findCandidateByEmail(candidate.getEmail()) == null) {
candidateRepository.save(candidate);
return true;
} else {
return false;
}
}
When trying to save (automatically) the Languages and the Frameworks, I would like to check in database if there's already a entry, and if exists, update only
the correspondent relational table.
Here's the Pojos:
CANDIDATE:
#Entity
#Table(name = "candidates")
public class Candidate {
#Id
#Column(name = "candidate_id")
#GeneratedValue
private Long cadet_Id;
#Column (name = "email")
private String email;
#Column (name = "name")
private String name;
#Column(name = "password")
private String password;
#Column (name = "motto")
private String motto;
#Column (name = "github")
private String github;
#Column (name = "linkedin")
private String linkedin;
#ManyToMany (cascade = {CascadeType.ALL})
#JoinTable(name = "candidate_languages",
joinColumns = #JoinColumn(name = "language_id"),
inverseJoinColumns = #JoinColumn(name = "candidate_id"))
private Set<Languages> languages;
#ManyToMany (cascade = {CascadeType.ALL})
#JoinTable(name = "candidate_frameworks",
joinColumns = #JoinColumn(name = "framework_id"),
inverseJoinColumns = #JoinColumn(name = "candidate_id"))
private Set<Frameworks> frameworks;
LANGUAGES
#Entity
#Table(name = "languages")
public class Languages {
#Id
#Column(name = "language_id")
#GeneratedValue
private Long language_Id;
#Column (name = "name")
private String name;
FRAMEWORKS:
#Entity
#Table(name = "Frameworks")
public class Frameworks {
#Id
#Column(name = "framework_id")
#GeneratedValue
private Long framework_Id;
#Column (name = "name", unique = true)
private String name;
I'm Using spring data and the default Repositorys for each class:
public interface FrameworkRepository extends CrudRepository<Frameworks,Long{}
Thanks for the help.

How to map entities with #EmbeddedId?

Does anyone know how to fix the mapping of entities?
Error is
Caused by: org.hibernate.AnnotationException: Column name ID of
com.test.TableAa not found in JoinColumns.referencedColumnName.
TableAa entity
#Entity
#Table(name = "TABLE_AA")
public class TableAa {
#EmbeddedId
private TableAaPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
//#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
//#JoinColumns({
//#JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false),
//#JoinColumn(name = "ACCOUNT_NUMBER", referencedColumnName = "ACCOUNT_NUMBER", insertable = false, updatable = false) })
#OneToMany(mappedBy = "tableAa", cascade = CascadeType.ALL)
private List<TableBb> tableBbList;
}
TableAaPk composite key
#Embeddable
public class TableAaPk implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="ID")
private String id;
#Column(name="ACCOUNT_NUMBER")
private String accountNumber;
}
TableBb entity
#Entity
#Table(name = "TABLE_BB")
public class TableBb {
#EmbeddedId
private TableBbPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
}
TableBbPk composite key
#Embeddable
public class TableBbPk implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name="ID")
private String id;
#Column(name="ACCOUNT_NUMBER")
private String accountNumber;
#Column(name="CODE")
private String code;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID", referencedColumnName = "ID", insertable = false, updatable = false),
#JoinColumn(name = "ACCOUNT_NUMBER", referencedColumnName = "ACCOUNT_NUMBER", insertable = false, updatable = false) })
private TableAa tableAa;
}
In your TAbleAa you should have your OneToMany mapping as follows:
#OneToMany(mappedBy = "pk.tableAa", cascade = CascadeType.ALL)
private List<TableBb> tableBbList;
You reference through the embeddable which name is pk.
I think your problem in this entity
#Entity
#Table(name = "TABLE_BB")
public class TableBb {
#EmbeddedId
private TableBbPk pk;
#Column(name = "FIRST_NAME")
private String first_name;
#Column(name = "LAST_NAME")
private String last_name;
// I think the solution is to add the relation #ManyToOne which mapped by in the other side
#ManyToOne // because u refere to this name (tableAa) in #OneToMany(mappedBy = "tableAa"...) in TableAa entity
private TableAa tableAa;
}

Nested n:m + attributes JPA

I have a strange need in a project. Joining two n:m+attributes table (I will present the behavior with dummy attributes).
FirstTable (idPlace, idAddress,idSchool, wage) joined 1:m;
SecondTable (idPlace, idAddress,idSchool, qty, idEnterprise)
EDIT (example schema):
Of course that I have the tables Place, Address, School, Enterprise with theirs respective Ids, gets, sets and attributes implemented in the entity classes.
CODE:
Place
#Entity
#Table(name = "Place")
public class Place implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idLine")
private Long idLine;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.place")
private List<FirstTable> firstTables;
}
Address
#Entity
#Table(name = "Address")
public class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idAddress")
private Long idAddress;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.address")
private List<FirstTable> firstTables;
}
School
#Entity
#Table(name = "School")
public class School implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idSchool")
private Long idSchool;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.school")
private List<FirstTable> firstTables;
}
FirstTable
#Entity
#Table(name = "FirstTable")
#AssociationOverrides({ #AssociationOverride(name = "pk.school", joinColumns = #JoinColumn(name = "idSchool")),
#AssociationOverride(name = "pk.address", joinColumns = #JoinColumn(name = "idAddress")),
#AssociationOverride(name = "pk.place", joinColumns = #JoinColumn(name = "idPlace")) })
public class FirstTable implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#EmbeddedId
protected FirstTablePK pk = new FirstTablePK();
}
FirstTablePK
#Embeddable
public class FirstTablePK implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#ManyToOne
private Address address;
#ManyToOne
private Place place;
#ManyToOne
private School school;
}
The above mentioned tables and joins are working perfectly. Now I want to join the FirstTable with the Second Table.
Enterprise
#Entity
#Table(name = "Enterprise")
public class Enterprise implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idEnterprise")
private Long idEnterprise;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "pk.enterprise")
private List secondTables;
}
Now for the SecondTable I've followed the same logic to connect to the Enterprise. For connecting with the FirstTable I've tried this:
#Entity
#Table(name = "SecondTable")
#AssociationOverrides({
#AssociationOverride(name = "pk.firstTable", joinTable = #JoinTable(
name = "FirstTable", inverseJoinColumns = {
#JoinColumn(name = "idSchool", referencedColumnName = "idSchool"),
#JoinColumn(name = "idAddress", referencedColumnName = "idAddress"),
#JoinColumn(name = "idPlace", referencedColumnName = "idPlace") })),
#AssociationOverride(name = "pk.enterprise", joinColumns = #JoinColumn(name = "idEnterprise")) })
public class SecondTable implements Serializable{}
Something is not working in my annotation, I'm trying to do an inverseJoin to the FirstTable table. The compilation shows this error:
"org.hibernate.AnnotationException: A component cannot hold properties split into 2 different tables"
I've tried to provide a MV example.
Thanks in advance and I really need your help.
Hours later and many tries before I've managed to solve the problem. Actually the solution was much simpler that I was thinking initially.
Here it is:
#AssociationOverride(name = "pk.firstTable", joinColumns = {
#JoinColumn(name = "idSchool"),
#JoinColumn(name = "idAddress"),
#JoinColumn(name = "idPlace") }),
#AssociationOverride(name = "pk.enterprise", joinColumns = #JoinColumn(name = "idEnterprise")) })

jpa many to many with additional column and composite key

I have 2 tables :folder(simple primary key) and document(composite primary key)
I want a join table named folder_documents which will contains the id of both tables with additional columns
There is my entities:
Folder
#Entity
#Table(name = "folder")
public class Folder {
#Id
#SequenceGenerator(name = "folder_seq_gen", sequenceName = "FOLDER_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "folder_seq_gen")
private long id;
#Column
private Date date;
#OneToMany(mappedBy = "folder_documents_compositeKey.folder",
cascade = CascadeType.ALL)
private Set<Folder_Documents> folder_documents;
Document
#Entity
#Table(name="document")
public class Document {
#EmbeddedId
private DocumentID documentCompositeKey;
#Column
private Date date;
DocumentID(composite key)
#Embeddable
public class DocumentID implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String id;
private String matricule;
Folder_Document ( join table)
#Entity
#Table(name = "folder_documents")
#AssociationOverrides({
#AssociationOverride(name = "folder_documents_compositeKey.folder",
joinColumns = #JoinColumn(name = "folder_id")),
#AssociationOverride(name = "folder_documents_compositeKey.document",
joinColumns = #JoinColumn(name = "doc_id" , referencedColumnName = "id")), // error mapping there
#AssociationOverride(name = "folder_documents_compositeKey.document",
joinColumns = #JoinColumn(name = "matricule" , referencedColumnName = "matricule"))})// error mapping there
public class Folder_Documents {
#EmbeddedId
private Folder_Documents_ID folder_documents_compositeKey = new Folder_Documents_ID();
#Column
private Date date;
#Column
private String status;
Folder_documents_id(composite key)
#Embeddable
public class Folder_Documents_ID implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#ManyToOne(cascade = CascadeType.ALL)
private Folder folder;
#ManyToOne(cascade = CascadeType.ALL)
private Document document;
The problem is i can't map the Document compositeKey in Folder_Documents' s #AssociationOverrides attributes because hibernate don't find the composite key id and matricule properties in Document . Folder references is fine .
There is the stacktrace:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(matricule) of com.renault.entity.Folder_Documents_ID.folder_documents_compositeKey.document referencing com.renault.entity.Document not mapped to a single property
Resolved , the syntax of the AssociationOverride annotation was wrong
Correct syntax :
AssociationOverrides({
#AssociationOverride(name = "folder_documents_compositeKey.folder", joinColumns = #JoinColumn(name = "folder_id")),
#AssociationOverride(name = "folder_documents_compositeKey.document", joinColumns = {
#JoinColumn(name = "doc_id" , referencedColumnName = "id") ,
#JoinColumn(name = "matricule" , referencedColumnName = "matricule") })})

Categories