I try to create a composite primary key but can't.
My attempt (there is the tutorial I used):
User entity:
#Entity
#Table(name = "user")
public class User {
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column
private String name;
//getters, setters, equals, hashcode
}
PersonalScore class:
#Entity
public class PersonalScore {
#EmbeddedId
private PersonalScoreId personalScoreId;
//getters, setters, equals, hashcode, constructors
}
PersonalScoreId class (Primary key):
#Embeddable
public class PersonalScoreId implements Serializable {
private User user;
private Date date;
//getters, setters, equals, hashcode, constructors (noargs included)
That's all. In the result I got the error:
> Caused by: javax.persistence.PersistenceException: [PersistenceUnit:
> default] Unable to build Hibernate SessionFactory; nested exception is
> org.hibernate.MappingException: Could not determine type for:
> com...model.dto.User, at table: personal_score, for columns:
> [org.hibernate.mapping.Column(user)]
From EmbeddedId:
Relationship mappings defined within an embedded id class are not supported.
What you need to do is replace the User field with a field for the user's id (private long userId), then use MapsId in your PersonalScore class to add a relation with User using the userId field from the embedded id.
Related
SOLVED
Metadata classes and Entity/Embeddable classes have different names. I just renamed them and now it fires up
I'm trying to map an entity on my DB with my jpa web application. The problem is that the entity got a 2 elements key and, also if i'm using an embeddable, after launching my app with tomcat, it displays this error:
Caused by: <openjpa-2.4.0-r422266:1674604 fatal user error> org.apache.openjpa.util.MetaDataException: The type "class it.cabel.aml.libb2b.cliente.jpa.entities.JpaKeyPK" has not been enhanced.
I'm changing the name of classes just for readability.
This is the JpaKeyPK class:
//import...
#Embeddable
public class JpaKeyPK implements Serializable {
#Column(name = "ID")
private Integer id;
#Column(name = "DATA_VARIAZIONE")
private Date dataVariazione;
public JpaKeyPK () {
}
public JpaKeyPK (Integer id, Date dataVariazione) {
this.id = id;
this.dataVariazione = dataVariazione;
}
// getters, setters, hashcode and equals implementation...
And this is the entity class:
#Entity
#Table(name = "TABLE_NAME")
public class JpaEntity{
#EmbeddedId
private JpaKeyPK pk;
//getters, setters, constructor...
I added both of them to my persistence.xml file and, when i try to do a clean install with maven, logs write this:
12670 App INFO [main] openjpa.Tool - Enhancer running on type "class it.jpa.entities.JpaEntity".
12671 App INFO [main] openjpa.Tool - Enhancer running on type "class it.jpa.entities.JpaKeyPK".
What's wrong?
I have entity classes like this structure:
Class Parent {
#EmbededId
private ParentId id;
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="parentDetails")
private List<Child> childDetails;
...
}
#Embeddable
Class ParentId {
private Integer pid1;
private Integer pid2;
private Integer pid3;
...
}
Class Child {
#EmbededId
private ChildId id;
#ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumns({
#JoinColumn(name="C_ID1" referencedColumnName="P_ID1")
#JoinColumn(name="C_ID2" referencedColumnName="P_ID2")
)}
private Parent parentDetails;
...
}
#Embeddable
Class ChildId {
private Integer cid1;
private Integer cid2;
private date cid3; // its a totally different field
...
}
I don't have any relationship with pid3 and cid3 as they are different. If I go with above design I am getting below error:
org.hibernate.AnnotationException: referencedColumnNames(P_ID1, P_ID2) of Child.parentDetails referencing Parent not mapped to a single property
If I comment pid3 then it works. So does that mean that I can't refer part of composite key as join columns? Is there any solution for it? I can't make changes to tables as they are legacy.
In my Spring boot - JPA application, I am trying to implement composite key :
#Entity
public class User
{
#Id
private String timeStamp;
#Id
private String firstName;
#Id
private String lastName;
}
This gives me error, saying :
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Composite-id class must implement Serializable: com.mua.testkeys.model.User
Even if I implement Serializable it gives me error.
How can I resolve this ?
Used : Spring + JPA + H2
Composite Key can be created with #IdClass as below.
User.class
#IdClass(UserPK.class)
#Table(name = "user")
#Entity
public class User {
#Id
private String timeStamp;
#Id
private String firstName;
#Id
private String lastName;
//remaining fields
// getters and setters
}
UserPK.class
public class UserPK {
private String timeStamp;
private String firstName;
private String lastName;
// constructors
// getters and setters
//implement euquels() and hashcode()
}
Define a Class for primary key with all keys as fields.
Implement equals() and hashcode() methods.
Annotate User class with #IdClass(UserPK.class)
Declare Id fields with #Id annotation
This is my sql table structure:
create table TBL_EMPLOYEE_FIVE(
EMP_ID integer generated always as identity(start with 50, increment by 4),
NAME varchar(50),
COUNTRY varchar(50),
MGR_ID integer,
MGR_COUNTRY varchar(50),
constraint PK_COMPOSIT_001AD primary key(EMP_ID,COUNTRY),
constraint FK_COMPO_00123 foreign key(MGR_ID,MGR_COUNTRY) references TBL_EMPLOYEE_FIVE
)
And this is my entity mapping:
#Entity
#Table(name="TBL_EMPLOYEE_FIVE")
#IdClass(EmployeeId.class)
public class EmployeeOne implements Serializable{
public EmployeeOne(){}
public EmployeeOne(String employeeName,String empCountry){
this.empCountry = empCountry;
this.employeeName = employeeName;
}
public EmployeeOne(String employeeName,String empCountry,EmployeeOne manager){
this.empCountry = empCountry;
this.employeeName = employeeName;
this.manager = manager;
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="EMP_ID")
private Integer employeeId;
#Id
#Column(name="COUNTRY")
private String empCountry;
#Column(name="NAME")
private String employeeName;
#ManyToOne( cascade= {CascadeType.PERSIST, CascadeType.PERSIST},
fetch= FetchType.LAZY,
targetEntity=EmployeeOne.class)
#JoinColumns({
#JoinColumn(name="MGR_ID",referencedColumnName="EMP_ID"),
#JoinColumn(name="MGR_COUNTRY",referencedColumnName="COUNTRY")
})
private EmployeeOne manager;
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.PERSIST},mappedBy="manager")
private Set<EmployeeOne> employees;
// getters and setters,
}
This is the the embedded id mapping,
#Embeddable
public class EmployeeId implements Serializable{
public EmployeeId(){}
public EmployeeId(Integer employeeId,String empCountry){
this.employeeId = employeeId;
this.empCountry = empCountry;
}
#Column(name="EMP_ID")
private Integer employeeId;
#Column(name="COUNTRY")
private String empCountry;
// only getters and implementation of hashcode and equals method
}
And this is what I am trying to run in my main method:
EmployeeOne manager = new EmployeeOne("Yousuf Ahmadinejad", "IRAN");
em.persist(manager);
But here i am getting an exception i.e.
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: Attempt to modify an identity column 'EMP_ID'.
It's not like i didn't understood the exception,
but why this exception occured in the first place? I already annotated it with #GenerateValue for Empid and I am not setting the empId manually. Does this exception occur because I have combined primary key as empId and country, and than the empId is autogenerated using Identity, hence its giving an exception ?
Can you please tell me whats going wrong
One more thing i want to add here is, if i removed #Column and #Embeddeble annotation for EmployeeId.java, and than run, i get an following exception,
Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.entities.derived.EmployeeId.employeeId
So just trying to find the solution to persist employee keeping the autogenerated Id as it is
First Hibernate does not generate id's for composite keys, so you should change EmployeeOne to:
#Id
//#GeneratedValue(strategy=GenerationType.IDENTITY) remove this line
#Column(name="EMP_ID")
private Integer employeeId;
Second that's not how you should implement EmployeeId composite key class. See: https://stackoverflow.com/a/3588400/1981720
Third, the exception is thrown by the database, not Hibernate. Check if you're getting the same exception with another database.
Maybe somebody can clarify what is wrong with the code below. When I create one-to-one association within embedded class (it is composite primary key) like in the code below:
#Entity
public class Test {
#EmbeddedId
private TestId id;
#Embeddable
public static class TestId implements Serializable {
private static final long serialVersionUID = 1950072763330622759L;
#OneToOne(optional = false)
#JoinColumn(name = "linkedTable_id")
private LinkedTable linkedTable;
}
..........
}
I get the following stack trace:
--------------------------------------------
Caused by: java.lang.NullPointerException
at org.hibernate.cfg.AnnotationBinder.bindOneToOne(AnnotationBinder.java:1867)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1286)
at org.hibernate.cfg.AnnotationBinder.fillComponent(AnnotationBinder.java:1662)
at org.hibernate.cfg.AnnotationBinder.bindId(AnnotationBinder.java:1695)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1171)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:706)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:452)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:268)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1121)
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1211)
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:154)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:847)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:178)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:235)
... 26 more
What is interesting why the sample above works if I change association type to many-to-one and doesn't work with one-to-one?
I wasn't aware this was possible but, according to the Hibernate Annotation reference documentation, it is (this is Hibernate specific though):
2.2.3.2.1. #EmbeddedId property
(...)
While not supported in JPA, Hibernate
lets you place your association
directly in the embedded id component
(instead of having to use the
#MapsId annotation).
#Entity
class Customer {
#EmbeddedId CustomerId id;
boolean preferredCustomer;
}
#Embeddable
class CustomerId implements Serializable {
#OneToOne
#JoinColumns({
#JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
#JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
User user;
String customerNumber;
}
#Entity
class User {
#EmbeddedId UserId id;
Integer age;
}
#Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
}
And with the code you provided, the following snippet just works for me:
LinkedTable linkedTable = new LinkedTable();
linkedTable.setId(1l);
session.persist(linkedTable);
session.flush();
Test.TestId testId = new Test.TestId();
testId.setLinkedTable(linkedTable);
Test test = new Test();
test.setId(testId);
session.persist(test);
session.flush();
Tested with Hibernate EM 3.4.0.GA, Hibernate Annotations 3.4.0.GA and Hibernate Core 3.3.0.SP1.
If it doesn't work for you, can you provide a bit more code allowing to reproduce the problem?