I have a Java EE application using JPA (EclipseLink) and Spring framework.
Everything worked fine in my persistence classes until I added Spring transaction management.
I have following entities (corresponding to the database tables) :
Project
#Entity
#Table(name="projet")
public class Projet implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_projet", unique=true, nullable=false)
private Integer idProjet;
#Column(name="nom_projet")
private String nomProjet;
/** The projet util droits. */
#OneToMany(mappedBy="projet", cascade={CascadeType.ALL})
private Set<ProjetUtilDroit> projetUtilDroits;
public Projet() {
}
...
}
User
#Entity
#Table(name="utilisateur")
public class Utilisateur implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The id utilisateur. */
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_utilisateur", unique=true, nullable=false)
private Integer idUtilisateur;
/** The nom utilisateur. */
#Column(name="nom_utilisateur", nullable=false, length=50)
private String nomUtilisateur;
//bi-directional many-to-one association to ProjetUtilDroit
/** The projet util droits. */
#OneToMany(mappedBy="utilisateur", cascade={CascadeType.REMOVE})
private Set<ProjetUtilDroit> projetUtilDroits;
...
}
Right
#Entity
#Table(name="droit")
public class Droit implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The id droit. */
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_droit", unique=true, nullable=false)
private Integer idDroit;
/** The type droit. */
#Column(name="type_droit", nullable=false, length=10)
private String typeDroit;
/**
* Instantiates a new droit.
*/
public Droit() {
}
...
}
And an association which links a user to a project with a specific right (ProjectUserRight)
#Entity
#Table(name="projet_util_droit")
public class ProjetUtilDroit implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The id. */
#EmbeddedId
private ProjetUtilDroitPK id;
//bi-directional many-to-one association to Droit
/** The droit. */
#ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name="id_droit")
private Droit droit;
//bi-directional many-to-one association to Projet
/** The projet. */
#MapsId("idProjet")
#ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name="id_projet")
private Projet projet;
//bi-directional many-to-one association to Utilisateur
/** The utilisateur. */
#MapsId("idUtilisateur")
#ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name="id_utilisateur")
private Utilisateur utilisateur;
...
}
The embedded id for the association:
#Embeddable
public class ProjetUtilDroitPK implements Serializable {
//default serial version id, required for serializable classes.
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The id projet. */
#Column(name="id_projet", unique=true, nullable=false)
private Integer idProjet;
/** The id utilisateur. */
#Column(name="id_utilisateur", unique=true, nullable=false)
private Integer idUtilisateur;
...
}
My method creating the project with its right:
public Projet createProject(String name, int idRight, int idUser) {
Projet project = new Projet();
project.setNomProjet(name);
ProjetUtilDroit pud = new ProjetUtilDroit();
Droit d = rightDao.findById(idRight);
pud.setDroit(d);
pud.setProjet(project);
Utilisateur user = userDao.findById(idUser);
pud.setUtilisateur(user);
if(user.getProjetUtilDroits() == null)
user.setProjetUtilDroits(new HashSet<ProjetUtilDroit>());
user.getProjetUtilDroits().add(pud);
Set<ProjetUtilDroit> pudSet = new HashSet<ProjetUtilDroit>();
pudSet.add(pud);
project.setProjetUtilDroits(pudSet);
project = projectDao.create(project);
return project;
}
It worked like a charm (persist the project and the associated user rights) until I add the annotation #Transactionnal above the "createProject" method...
Now I get this error:
Avertissement: StandardWrapperValve[dispatcher]: PWC1406: Servlet.service() for servlet dispatcher threw exception
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST:
*****Project right****
User name: userName Right: read.
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:304)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:702)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:433)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:780)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.performPreQueryFlush(EJBQueryImpl.java:1298)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:434)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:742)
at com.dao.BasicDAO.findAll(BasicDAO.java:92)
at com.dao.BasicDAO.create(BasicDAO.java:103)
at com.services.ProjectService.createProject(ProjectService.java:48)
at com.services.ProjectService$$FastClassByCGLIB$$67c85b9f.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at com.services.ProjectService$$EnhancerByCGLIB$$398fa756.createProject()
at com.servlet.Test.handleCreateProject(Test.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)
The only solution I imagine is to create the project within one transaction and save its rights separately within another transaction. Is that the only solution or does anybody have another suggestion?
Which object was not persisted? Include the full exception.
You need to either mark the relationship to the object as cascade persist, or call persist on the object before persisting the project.
Related
Bidirectional ManyToMany mapping is using EMPLOYEE_PROJECT relation table instead of EMP_PROJ table described in mapping. EMPLOYEE_PROJECT does not exist on db. Eclipselink version is 2.7.3 and jpa version is 2.2
#Entity
public class Employee extends Base implements Serializable {
/** explicit set serialVersionUID */
private static final long serialVersionUID = 1L;
#Column(name = "FIRSTNAME")
private String firstname;
#ManyToMany
#JoinTable(name = "EMP_PROJ", joinColumns = #JoinColumn(name = "EMP_ID"), inverseJoinColumns = #JoinColumn(name = "PROJ_ID"))
private List<Project> projects;
public List<Project> getProjects() {
return projects;
}
public void setProjects(List<Project> projects) {
this.projects = projects;
Project Class
#Entity
public class Project extends Base implements Serializable {
/** explicit set serialVersionUID */
private static final long serialVersionUID = 1L;
#Column(name = "NAME")
private String name;
#ManyToMany(mappedBy="projects")
Set<Employee> employees = new HashSet<Employee>();
Problem is when query run
#Test
public void save_employee(){
EntityManager em = emf.createEntityManager();
Employee emp1 = em.find(Employee.class, new Integer(1));
Project p = new Project();
p.setName("Name1");
p.getEmployees().add(emp1);
p = em.merge(p);
assertNotNull(p);
Employee emp2 = em.find(Employee.class, new Integer(1));
assertEquals(1, emp2.getProjects().size());
em.close();
}
Following exception:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: Table "EMPLOYEE_PROJECT" not found; SQL statement:
SELECT t1.ID, t1.DESCRIPTION, t1.NAME, t1.VERSION FROM EMPLOYEE_PROJECT t0, PROJECT t1 WHERE ((t0.Employee_ID = ?) AND (t1.ID = t0.projects_ID)) [42102-197]
Error Code: 42102
Base.java code is as following
#MappedSuperclass
public class Base {
protected int id;
protected int version;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Version
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
SO, I got 2 entities : InitialSituation, having ManytoOne relating with Universe entity.
In the form of InitialSituation, there a select for Universe :
<h:selectOneMenu id="universe" value="#{initialSituationController.initialSituation.universe}" >
<f:selectItems value="#{universeBean.selectItems}" />
</h:selectOneMenu>
Entities (using JPA annotation) :
#Entity
#Table(name = "initial_situation")
public class InitialSituation implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "initial_situation_id_seq")
#SequenceGenerator(name = "initial_situation_id_seq", sequenceName = "initial_situation_id_seq", allocationSize = 1)
#Column(name = "id_initial_situation")
protected int idInitialSituation;
protected String name;
protected String content;
protected boolean happy;
#ManyToOne
#JoinColumn(name = "id_universe")
protected Universe universe;
// Getters and setters
}
#Entity
#Table(name = "universe")
public class Universe implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="universe_id_seq")
#SequenceGenerator(name="universe_id_seq", sequenceName="universe_id_seq", allocationSize=1)
#Column( name = "id_universe" )
protected int idUniverse;
#Column
protected String name;
#Column
protected String content;
#OneToMany(mappedBy = "universe")
protected List<InitialSituation> initialSituations;
public List<InitialSituation> getInitialSituations() {
return initialSituations;
}
public void setInitialSituations(List<InitialSituation> initialSituations) {
this.initialSituations = initialSituations;
}
#Override
public String toString(){
return this.getName();
}
}
The select, in the rendered HTML, has correct values and labels. But the binding between selectOneMenu and value="#{initialSituationController.initialSituation.universe}" is not working.
Nevertheless, InitialSituation has a Universe initiated, I verified.
Why the binding is not working ? Thank you !
NB : I can't use another tag that
I've explained my scenario through simple Parent Child tables.
My composite primary key is also a composite foreign key referencing Parent table.
create table parent(
code varchar(10) not null,
id int not null,
parentcol varchar(10),
primary key(code,id)
);
create table child(
code varchar(10) not null,
id int not null,
childcol varchar(10) not null,
primary key(code, id),
foreign key(code, id) references parent(code,id)
);
Entities created (this is through Eclipse JPA plugin)
#Entity
#Table(name="parent")
#NamedQuery(name="Parent.findAll", query="SELECT p FROM Parent p")
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ParentPK id;
#Column(length=10)
private String parentcol;
//bi-directional one-to-one association to Child
#OneToOne(mappedBy="parent")
private Child child;
public Parent() {
}
/* getters and setters */
}
#Embeddable
public class ParentPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(unique=true, nullable=false, length=10)
private String code;
#Column(unique=true, nullable=false)
private int id;
/* getters and setters */
/** Overridden equals and hashcode **/
}
#Entity
#Table(name="child")
#NamedQuery(name="Child.findAll", query="SELECT c FROM Child c")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ChildPK id;
#Column(nullable=false, length=10)
private String childcol;
//bi-directional one-to-one association to Parent
#OneToOne
#JoinColumns({
#JoinColumn(name="code", referencedColumnName="code", nullable=false, insertable=false, updatable=false),
#JoinColumn(name="id", referencedColumnName="id", nullable=false, insertable=false, updatable=false)
})
private Parent parent;
/* getters and setters */
}
#Embeddable
public class ChildPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(insertable=false, updatable=false, unique=true, nullable=false, length=10)
private String code;
#Column(insertable=false, updatable=false, unique=true, nullable=false)
private int id;
/* overridden equals and hashcode */
I am using Spring data to save my entities as below. Parent table consist of a record with code as "code" and Id as 1.
Child child = new Child();
ChildPK childPK = new ChildPK();
childPK.setCode("code");
childPK.setId(1);
child.setId(childPK);
child.setChildcol("child1");
childRepository.save(child);
It succeeds with the 1st run when it has to insert a new record. But the issue is on the 2nd run when it has to update let's say with,
child.setChildcol("child2");
I face an error
HHH000327: Error performing load command : org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.xebia.eTechLog.entities.Parent. Expected: class com.xebia.eTechLog.entities.ParentPK, got class com.xebia.eTechLog.entities.ChildPK
In case I try to give a reference of ParentPk in the Child table as
#Entity
#Table(name="child")
#NamedQuery(name="Child.findAll", query="SELECT c FROM Child c")
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ParentPK id;
#Column(nullable=false, length=10)
private String childcol;
//bi-directional one-to-one association to Parent
#OneToOne
#JoinColumns({
#JoinColumn(name="code", referencedColumnName="code", nullable=false, insertable=false, updatable=false),
#JoinColumn(name="id", referencedColumnName="id", nullable=false, insertable=false, updatable=false)
})
private Parent parent;
It does work, but it won't in case there are more fields in the Parent class, which is my real scenario.
You should use a derived identity. Which means you should indicate that the child's reference to its parent maps the child's ID (with a #MapsId annotation):
#Entity
public class Child implements Serializable {
#EmbeddedId
private ChildPK id;
#Column(nullable=false, length=10)
private String childcol;
#OneToOne
#MapsId // <<< NB
#JoinColumns({
#JoinColumn(name="code", referencedColumnName="code"),
#JoinColumn(name="id", referencedColumnName="id")
})
private Parent parent;
...
}
Derived identities are discussed in the JPA 2.1 spec in section 2.4.1.
I have an issue with updating persistent objects. I have two objects "Admission" and "Location" as follows:
#Entity
#Table(name = "Admissions")
public class Admission implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(optional=false)
#JoinColumn(name="DemographicId", unique = true, nullable=false)
private Demographic demographic;
#OneToOne(optional=false)
#JoinColumn(name="VisitId", unique = true, nullable=false)
private Visit visit;
#OneToOne(optional=false)
#JoinColumn(name="LocationId", nullable=false)
private Location location;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "Updated", unique = false, nullable = false)
private Date updated;
#Entity
#Table(name = "Locations")
public class Location implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JoinColumn(name="FacilityId", nullable=true)
private Facility facility;
#JoinColumn(name="WardId", nullable=true)
private Ward ward;
#JoinColumn(name="RoomId", nullable=true)
private Room room;
#JoinColumn(name="BedId", nullable=true)
private Bed bed;
If I create an Admission and save it, all is well. If I then retrieve the Admission Update the Location to a new Location object the Admission does not save/update. The code I am using to save is:
public void transfer(MSH msh, PV1 pv1, PV2 pv2) {
String visitNumber = pv1.getVisitNumber().getIDNumber().getValue();
Visit myVisit = visitService.findByVisitNumber(visitNumber);
if (myVisit == null) {
log.debug("Unable to transfer if we have no Visit");
return;
}
Admission myAdmission = admissionService.findByVisit(myVisit);
myAdmission.setLocation(getLocation(msh, pv1));
}
I have tried doing a final save and flush (which does not seem to work), but understand that this should not be necessary.
An example of my service class
#Service
public class LocationServiceImpl implements LocationService {
#Resource
private LocationRepository repository;
#Transactional
public Location create(Location location) {
Location created = location;
return unique(created);
}
#Transactional
public Location findByLocation(Location location) {
return repository.findByLocation(location.getFacility(),
location.getWard(), location.getRoom(), location.getBed());
}
#Transactional
private Location unique(Location location) {
Location found = findByLocation(location);
if (found == null) {
return repository.save(location);
}
return found;
}
}
It seems that
public void transfer(MSH msh, PV1 pv1, PV2 pv2) {
Is not being executed within a transaction, please add #Transactional to your service class.
I am working on a JPA project. I need to use a #OneToMany mapping on a class that has three primary keys. You can find the errors and the classes after this.
javax.persistence.PersistenceException: No Persistence provider for EntityManager named JTA_pacePersistence: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
javax.persistence.PersistenceException
javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
Exception Description: predeploy for PersistenceUnit [JTA_pacePersistence] failed.
Internal Exception: Exception [TOPLINK-7220] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
Exception Description: The #JoinColumns on the annotated element [private java.util.Set isd.pacepersistence.common.Action.permissions] from the entity class [class isd.pacepersistence.common.Action] is incomplete. When the source entity class uses a composite primary key, a #JoinColumn must be specified for each join column using the #JoinColumns. Both the name and the referenceColumnName elements must be specified in each such #JoinColumn.
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:643)
at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:196)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
at isd.pacepersistence.common.DataMapper.(Unknown Source)
at isd.pacepersistence.server.MainServlet.getDebugCase(Unknown Source)
at isd.pacepersistence.server.MainServlet.doGet(Unknown Source)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:718)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:831)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:411)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:290)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:271)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:202)
Here is the source code of my classes :
Action :
#Entity
#Table(name="action")
public class Action {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int num;
#ManyToOne(cascade= { CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REFRESH })
#JoinColumn(name="domain_num")
private Domain domain;
private String name;
private String description;
#OneToMany
#JoinTable(name="permission", joinColumns= { #JoinColumn(name="action_num", referencedColumnName="action_num", nullable=false, updatable=false) }, inverseJoinColumns= { #JoinColumn(name="num") })
private Set<Permission> permissions;
public Action() {
}
Permission :
#SuppressWarnings("serial")
#Entity
#Table(name="permission")
public class Permission implements Serializable {
#EmbeddedId
private PermissionPK primaryKey;
#ManyToOne
#JoinColumn(name="action_num", insertable=false, updatable=false)
private Action action;
#ManyToOne
#JoinColumn(name="entity_num", insertable=false, updatable=false)
private isd.pacepersistence.common.Entity entity;
#ManyToOne
#JoinColumn(name="class_num", insertable=false, updatable=false)
private Clazz clazz;
private String kondition;
public Permission() {
}
PermissionPK :
#SuppressWarnings("serial")
#Entity
#Table(name="permission")
public class Permission implements Serializable {
#EmbeddedId
private PermissionPK primaryKey;
#ManyToOne
#JoinColumn(name="action_num", insertable=false, updatable=false)
private Action action;
#ManyToOne
#JoinColumn(name="entity_num", insertable=false, updatable=false)
private isd.pacepersistence.common.Entity entity;
#ManyToOne
#JoinColumn(name="class_num", insertable=false, updatable=false)
private Clazz clazz;
private String kondition;
public Permission() {
}
Good morning,
After a long day searching how JPA and #OneToMany works with composite PK, I did find a solution. In order to make it work, I used the parameter mappedBY of #OneToMany. As you can see in the code sample, I mapped the Set of Permission with the attribute action of the class Permission. And that's it! Simple when you know it!
FF
Action Class :
#Entity
#Table(name="action")
public class Action {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int num;
#ManyToOne(cascade= { CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REFRESH })
#JoinColumn(name="domain_num")
private Domain domain;
private String name;
private String description;
#OneToMany(mappedBy="action")
private Set<Permission> permissions;
Permission Class
#SuppressWarnings("serial")
#Entity
#Table(name="permission")
public class Permission implements Serializable {
#EmbeddedId
private PermissionPK primaryKey;
#ManyToOne
#JoinColumn(name="action_num", insertable=false, updatable=false)
private Action action;
The error message seems pretty clear: you need to declare the three columns of your composite PK as #JoinColum and the name and referenceColumnName must be specified for each. I didn't test the mapping but try this:
#OneToMany
#JoinTable(name="permission", joinColumns= {
#JoinColumn(name="col1", referencedColumnName="col1", nullable=false, updatable=false),
#JoinColumn(name="col2", referencedColumnName="col2", ...),
#JoinColumn(name="col3", referencedColumnName="col3", ...)
}, inverseJoinColumns= { #JoinColumn(name="num") })
private Set<Permission> permissions;