I have 5 tables every table has relation one to many with the next table
Project_t -> project_level1_t -> project_level2_t -> project_level3_t -> project_level4_t
I want to user hibernate with these tables
CREATE TABLE project_t
(
projectid serial NOT NULL,
address1 character varying(128),
postcode character varying(7),
city character varying(64),
level_four_name character varying(128),
CONSTRAINT project_t_pkey PRIMARY KEY (projectid),
CONSTRAINT projectcode_unique UNIQUE (projectcode)
)
And project_level1_t
CREATE TABLE project_level1_t
(
projectlevel1id integer NOT NULL DEFAULT nextval('project_level1_t_projectlevel1pk_seq'::regclass),
levelname character varying(256),
projectid integer,
CONSTRAINT project_level1_t_pkey PRIMARY KEY (projectlevel1id),
CONSTRAINT project_level1_t_project_t_fkey FOREIGN KEY (projectid)
REFERENCES project_t (projectid) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
And project_level2_t
CREATE TABLE project_level2_t
(
projectlevel2id integer NOT NULL DEFAULT nextval('project_level2_t_projectlevel2_seq'::regclass),
levelname character varying(256),
projectlevel1id integer,
CONSTRAINT project_level2_t_pkey PRIMARY KEY (projectlevel2id),
CONSTRAINT project_level2_t_projec_level_1_fkey FOREIGN KEY (projectlevel1id)
REFERENCES project_level1_t (projectlevel1id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
And this is the Repository files
package ma.eurnet.mp.tables.model;
import javax.persistence.GenerationType;
#JsonAutoDetect
#Entity
#Table(name = "project_t")
public class ProjectRepository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectRepository() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "projectid")
private Long projectId;
#OneToMany(fetch = FetchType.EAGER, mappedBy="project")
#JsonIgnore
private List<ProjectLevel1Repository> projectlevel1 = new ArrayList<ProjectLevel1Repository>();
public Long getProjectId() {
return projectId;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public List<ProjectLevel1Repository> getProjectlevel1() {
return projectlevel1;
}
public void setProjectlevel1(List<ProjectLevel1Repository> projectlevel1) {
this.projectlevel1 = projectlevel1;
}
and
package ma.eurnet.mp.tables.model;
#JsonAutoDetect
#Entity
#SequenceGenerator(name = "projectLevel1Sequence", sequenceName = "project_level1_t_projectlevel1pk_seq", allocationSize = 1)
#Table(name="project_level1_t")
public class ProjectLevel1Repository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectLevel1Repository() {
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "projectLevel1Sequence")
#Column(name = "projectlevel1id")
private Long projectLevel1Id;
#ManyToOne
#JoinColumn(name="projectid", referencedColumnName = "projectid")
#JsonIgnore
private ProjectRepository project;
#OneToMany(fetch = FetchType.EAGER, mappedBy="projectlevel1id")
#JsonIgnore
private List<ProjectLevel2Repository> projectlevel2 = new ArrayList<ProjectLevel2Repository>();
public List<ProjectLevel2Repository> getProjectlevel2() {
return projectlevel2;
}
public Long getProjectLevel1Id() {
return projectLevel1Id;
}
public void setProjectLevel1Id(Long projectLevel1Id) {
this.projectLevel1Id = projectLevel1Id;
}
public ProjectRepository getProject() {
return project;
}
public void setProject(ProjectRepository project) {
this.project = project;
}
}
And
package ma.eurnet.mp.tables.model;
import java.io.Serializable;
#JsonAutoDetect
#Entity
#SequenceGenerator(name = "projectLevel2Sequence", sequenceName = "project_level2_t_projectlevel2_seq", allocationSize = 1)
#Table(name="project_level2_t")
public class ProjectLevel2Repository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectLevel2Repository() {
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "projectLevel2Sequence")
#Column(name = "projectlevel2id")
private Long projectLevel2Id;
#Column(name = "levelname")
private String levelName;
#Column(name = "created_by")
private String createdBy;
#Column(name = "creation_date")
private String creationDate;
#ManyToOne
#JoinColumn(name="projectlevel1id", referencedColumnName = "projectlevel1id")
#JsonIgnore
private ProjectLevel1Repository projectlevel1id;
public Long getProjectLevel2Id() {
return projectLevel2Id;
}
public void setProjectLevel2Id(Long projectLevel2Id) {
this.projectLevel2Id = projectLevel2Id;
}
public String getLevelName() {
return levelName;
}
public void setLevelName(String levelName) {
this.levelName = levelName;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public String getCreationDate() {
return creationDate;
}
public void setCreationDate(String creationDate) {
this.creationDate = creationDate;
}
public ProjectRepository getProjectlevel1id() {
return projectlevel1id;
}
public void setProjectlevel1id(ProjectRepository projectlevel1id) {
this.projectlevel1id = projectlevel1id;
}
}
I want to save each entity by himself so if run this code
ProjectRepository projectRepository = projectService.getProjectById(Long.parseLong(projectId));
ProjectLevel1Repository projectLevel1Repository = new ProjectLevel1Repository();
projectLevel1Repository.setProject(projectRepository);
projectLevel1Repository.setLevelName(level1Name);
projectLevel1Service.saveOrUpdateRepository(projectLevel1Repository);
ProjectLevel2Repository projectLevel2Repository = new ProjectLevel2Repository();
projectLevel2Repository.setLevelName("Test Level 2");
projectLevel2Repository.setProjectlevel1id(projectLevel1Repository);
projectLevel2Service.saveOrUpdateRepository(projectLevel2Repository);
I want to save one projectLevel1 and one projectLevel2 but what is happening now two projectLevel1 save with one projectLevel2
Related
One To Many with Parent composite primary key is part of child primary key issue. Throwing Exceptions with the below code snippets
Sample JSON Embedded Data as follows:
{
"pt_reg_no": "1000", //Serial number generation
"game_year": "G12021",
"name": "myname",
"eventDetails": [{
"major_event_code": "A",
"sub_event_code": "A7",
"category_code": "MO"
},
{
"major_event_code": "B",
"sub_event_code": "B7",
"category_code": "WO"
}
]
}
Participant can register for multiple Events:
Participant (Composite Key) - pt_reg_no, game_year
EventDetails (Composite Key) - pt_reg_no, game_year, sub_event_code, category_code
//Parent Class IDclass
public class ParticipantKey implements Serializable {
private Long pt_reg_no;
private String game_year;
}
#IdClass(ParticipantKey.class)
public class ParticipantModel {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "participantseq"
)
#SequenceGenerator(
name = "participantseq",
allocationSize = 1
)
private Long pt_reg_no;
#Id
private String game_year = 'G12021';
#OneToMany(mappedBy = "participantModel", orphanRemoval = true, cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
private Set<EventDetailsModel> eventDetails = new HashSet<>();
public Set<EventDetailsModel> getEventDetails() {
return eventDetails;
}
public void setEventDetails(Set<EventDetailsModel> eventDetails) {
this.eventDetails = eventDetails;
for (EventDetailsModel b : eventDetails) {
b.setParticipantModel(this);
}
}
}
//Child class IDclass
public class ParticipantEventDetailsId implements Serializable {
private ParticipantKey participantModel;
private String sub_event_code;
private String category_code;
}
public class EventDetailsModel {
#Id
#Column(name = "sub_event_code")
private String sub_event_code;
#Id
#Column(name = "category_code")
private String category_code;
#Id
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "pt_reg_no", referencedColumnName = "pt_reg_no"),
#JoinColumn(name = "game_year", referencedColumnName = "game_year")
})
private ParticipantModel participantModel;
public ParticipantModel getParticipantModel() {
return participantModel;
}
public void setParticipantModel(ParticipantModel participantModel) {
this.participantModel = participantModel;
}
}
//---------------------------------------------------
//JSON input data received into ParticipantModel from #requestBody
public class FormDataObjects {
private ParticipantModel formData;
#JsonCreator
public FormDataObjects(ParticipantModel formData) {
this.formData = formData;
}
}
//Controller Entry point
#RequestMapping(path = "/participantData", method = RequestMethod.POST)
#Transactional
public ResponseEntity<?> participantRegistration(#Valid #RequestBody FormDataObjects values) {
ParticipantModel participant = values.getFormData();
participant.setGame_year(new SimpleDateFormat("yyyy").format(new Date()) + GenricData.game);
ParticipantModel person = participantRepository.save(participant);
if (person == null) {
return ResponseEntity.ok("Participant is not inserted");
} else {
Set<EventDetailsModel> eventDetails = participant.getEventDetails();
if (eventDetails.size() > 0) {
eventDetails.forEach(event -> {
//event.setPt_reg_no(person.getPt_reg_no());
//event.setGame_year(person.getGame_year());
//event.setParticipantModel(participant);
entityManager.persist(event);
entityManager.flush();
entityManager.clear();
});
}
}
return ResponseEntity.ok("inserted");
}
You can try a "derived identity" by mapping your details class like this:
public class ParticipantEventDetailsId implements Serializable {
private String sub_event_code;
private String category_code;
private ParticipantKey participantModel; // matches name of attribute and type of ParticipantModel PK
}
public class EventDetailsModel {
#Id
#Column(name = "sub_event_code")
private String sub_event_code;
#Id
#Column(name = "category_code")
private String category_code;
#Id
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "pt_reg_no", referencedColumnName = "pt_reg_no"),
#JoinColumn(name = "game_year", referencedColumnName = "game_year")
})
private ParticipantModel participantModel;
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
Alternative solution to OneToMany mapping when parent has composite key and serial number generation is also required at parent
Use #Transient annotation at Set or List Child Entities
1)save Parent entity with above annotation helps jpa to skip List/Set of EventsDetailsModel from saving
2) Iterate Child and get Parent composite key values which are already saved and persist child data along with childs key attributes.
//Parent Class IDclass
public class ParticipantKey implements Serializable {
private Long pt_reg_no;
private String game_year;
}
#IdClass(ParticipantKey.class)
public class ParticipantModel {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "participantseq"
)
#SequenceGenerator(
name = "participantseq",
allocationSize = 1
)
private Long pt_reg_no;
#Id
private String game_year = 'G12021';
#Transient //Find exact path for Transient
private Set<EventDetailsModel> eventDetails = new HashSet<>();
public Set<EventDetailsModel> getEventDetails() {
return eventDetails;
}
}
//Child class IDclass
public class ParticipantEventDetailsId implements Serializable {
private Long pt_reg_no;
private String game_year;
private String sub_event_code;
private String category_code;
}
public class EventDetailsModel {
#Id
#Column(name = "sub_event_code")
private String sub_event_code;
#Id
#Column(name = "category_code")
private String category_code;
#Id
private Long pt_reg_no;
#Id
private String game_year;
}
//---------------------------------------------------
//JSON input data received into ParticipantModel from #requestBody
public class FormDataObjects {
private ParticipantModel formData;
#JsonCreator
public FormDataObjects(ParticipantModel formData) {
this.formData = formData;
}
}
//Controller Entry point
#RequestMapping(path = "/participantData", method = RequestMethod.POST)
#Transactional
public ResponseEntity<?> participantRegistration(#Valid #RequestBody FormDataObjects values) {
ParticipantModel participant = values.getFormData();
participant.setGame_year(new SimpleDateFormat("yyyy").format(new Date()) + GenricData.game);
ParticipantModel person = participantRepository.save(participant);
if (person == null) {
return ResponseEntity.ok("Participant is not inserted");
} else {
Set<EventDetailsModel> eventDetails = participant.getEventDetails();
if (eventDetails.size() > 0) {
eventDetails.forEach(event -> {
event.setPt_reg_no(person.getPt_reg_no());
event.setGame_year(person.getGame_year());
entityManager.persist(event);
entityManager.flush();
entityManager.clear();
});
}
}
return ResponseEntity.ok("inserted");
}
I have something similar to this:
#Entity
#Table(name = "claim", schema = "test")
public class Claim implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idClaim", unique = true, nullable = false)
private Integer idClaim;
#OneToOne(mappedBy = "claim", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JsonManagedReference
private ClaimReturnInfo claimReturnInfo;
#Column(name = "notes")
private String notes;
// Getters and setters
}
#Entity
#Table(name = "claim_returninfo", schema = "test")
public class ClaimReturnInfo implements Serializable {
#Id
#Column(name = "Claim_idClaim")
private Integer id;
#MapsId("Claim_idClaim")
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Claim_idClaim")
#JsonBackReference
private Claim claim;
#Column(name = "description")
private String description;
// Getters and setters
}
ClaimReturnInfo Id is not autogenerated because we want to propagate the Id from its parent (Claim). We are not able to do this automatically and we are getting this error: ids for this class must be manually assigned before calling save() when 'cascade' is executed in ClaimReturnInfo .
Is it possible to map Claim Id into ClaimReturnInfo Id or should we do this manually?
Even if we set this ID manually on claimReturnInfo and we can perform updates, we still get this error when trying to create a new Claim:
// POST -> claimRepository.save() -> Error
{
"notes": "Some test notes on a new claim",
"claimReturnInfo": {
"description": "Test description for a new claimReturnInfo"
}
}
In the ServiceImplemetation:
#Override
#Transactional
public Claim save(Claim claim) throws Exception {
if(null != claim.getClaimReturnInfo()) {
claim.getClaimReturnInfo().setId(claim.getIdClaim());
}
Claim claimSaved = claimRepository.save(claim);
return claimSaved;
}
I have tried using the following mappings and from your comments it was apparent that Json object is populated correctly.
I have noticed that the annotation #MapsId is the culprit.If you check the documentation of #MapsId annotation it says
Blockquote
The name of the attribute within the composite key
* to which the relationship attribute corresponds. If not
* supplied, the relationship maps the entity's primary
* key
Blockquote
If you change #MapsId("Claim_idClaim") to #MapsId it will start persisting your entities.
import javax.persistence.*;
#Entity
#Table(name = "CLAIM")
public class Claim {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idClaim", unique = true, nullable = false)
private Long idClaim;
#Column(name = "notes")
private String notes;
#OneToOne(mappedBy = "claim", cascade = CascadeType.ALL, optional = false)
private ClaimReturnInfo claimReturnInfo;
public Long getIdClaim() {
return idClaim;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public ClaimReturnInfo getClaimReturnInfo() {
return claimReturnInfo;
}
public void setClaimReturnInfo(ClaimReturnInfo claimReturnInfo) {
if (claimReturnInfo == null) {
if (this.claimReturnInfo != null) {
this.claimReturnInfo.setClaim(null);
}
} else {
claimReturnInfo.setClaim(this);
}
this.claimReturnInfo = claimReturnInfo;
}
}
package com.hiber.hiberelations;
import javax.persistence.*;
#Entity
#Table(name = "CLAIM_RETURN_INFO")
public class ClaimReturnInfo {
#Id
#Column(name = "Claim_idClaim")
private Long childId;
#Column(name = "DESCRIPTION")
private String description;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Claim_idClaim")
private Claim claim;
public Long getChildId() {
return childId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Claim getClaim() {
return this.claim;
}
public void setClaim(Claim claim) {
this.claim = claim;
}
}
I have a relation between a parent and child table in which, the parent table has a single primary key and the child table has a composite primary key. However only one of the columns in the child table is referenced to the parent table.
My hibernate classes are wired up as such:
Parent Table
#Entity
#Table(name = "snippet")
public class SnippetEntity implements Serializable{
private static final long serialVersionUID = -3220451853395334879L;
#Id
#Column(name = "snpt_id", nullable=false, updatable=false)
#JsonBackReference
private String snippetId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "cretn_ts")
private Date creationTimeStamp;
#Column(name = "cretn_user_id")
private String creationUserId;
public String getSnippetId() {
return snippetId;
}
public void setSnippetId(String snippetId) {
this.snippetId = snippetId;
}
public Date getCreationTimeStamp() {
return creationTimeStamp;
}
public void setCreationTimeStamp(Date creationTimeStamp) {
this.creationTimeStamp = creationTimeStamp;
}
public String getCreationUserId() {
return creationUserId;
}
public void setCreationUserId(String creationUserId) {
this.creationUserId = creationUserId;
}
#Override
public String toString() {
return "SnippetEntity{" +
"snippetId='" + snippetId + '\'' +
'}';
}
}
Child Table
#Entity
#Table(name = "snippet_detail")
public class SnippetDetailEntity implements Serializable {
private static final long serialVersionUID = -7470223455753164243L;
#Id
#Column(name = "lang_cd", nullable=false, updatable=false)
private String language;
#Column(name = "snpt_type_cd")
private String snippetType;
#Column(name = "snpt_desc")
private String snippetDescription;
#Column(name = "snpt_txt")
private String snippetText;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "cretn_ts")
private Date creationTimeStamp;
#Column(name = "cretn_user_id")
private String creationUserId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updt_ts")
private Date updatedTimeStamp;
#Column(name = "updt_user_id")
private String updatedUserId;
#ManyToOne
#JoinColumn(name="snpt_id")
#JsonManagedReference
private SnippetEntity snippetEntity;
public SnippetDetailEntity() {}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getSnippetType() {
return snippetType;
}
public void setSnippetType(String snippetType) {
this.snippetType = snippetType;
}
public String getSnippetDescription() {
return snippetDescription;
}
public void setSnippetDescription(String snippetDescription) {
this.snippetDescription = snippetDescription;
}
public String getSnippetText() {
return snippetText;
}
public void setSnippetText(String snippetText) {
this.snippetText = snippetText;
}
public Date getCreationTimeStamp() {
return creationTimeStamp;
}
public void setCreationTimeStamp(Date creationTimeStamp) {
this.creationTimeStamp = creationTimeStamp;
}
public String getCreationUserId() {
return creationUserId;
}
public void setCreationUserId(String creationUserId) {
this.creationUserId = creationUserId;
}
public Date getUpdatedTimeStamp() {
return updatedTimeStamp;
}
public void setUpdatedTimeStamp(Date updatedTimeStamp) {
this.updatedTimeStamp = updatedTimeStamp;
}
public String getUpdatedUserId() {
return updatedUserId;
}
public void setUpdatedUserId(String updatedUserId) {
this.updatedUserId = updatedUserId;
}
public SnippetEntity getSnippetEntity() { return snippetEntity; }
public void setSnippetEntity(SnippetEntity snippetEntity) { this.snippetEntity = snippetEntity; }
#Override
public String toString() {
return "SnippetDetailEntity{" +
"language='" + language + '\'' +
", snippetType='" + snippetType + '\'' +
", snippetDescription='" + snippetDescription + '\'' +
", snippetText='" + snippetText + '\'' +
", creationTimeStamp=" + creationTimeStamp +
", creationUserId='" + creationUserId + '\'' +
", updatedTimeStamp=" + updatedTimeStamp +
", updatedUserId='" + updatedUserId + '\'' +
", snippetEntity=" + snippetEntity +
'}';
}
}
The call to get all snippet_detail is:
List<SnippetDetailEntity> snippetEntities = dbService.getAll(SnippetDetailEntity.class);
public <T> List<T> getAll(Class<T> clazz) {
return getSession().createCriteria(clazz).list();
}
There are 378 records in snippet_detail. So, my problem is, when I do a list to get all rows from snippet_detail I get two unique records (the first two that match the primary keys on this table) from snippet_detail and these records are duplicated multiple times. The total number of records are still 378, but these 378 records are made of the two records duplicated multiple times. What I am totally confused about and I admit this maybe due to my understanding of hibernate is why is this happening? I have read through a lot of posts and they all talk about hibernate doing an outer join. Is there something wrong I am doing? If so, what do I do to fix this?
UPDATE:
Reading through some more blogs and post I realized that I have a composite key in my snippet_detail and the way to handle that with hibernate it to use the #Embeddable annotations. I created a #Embeddable class that has the snpt_id and lang_cd. I modified my snippet_detail entity class to use the #Embeddable class. I also moved the #ManyToOne join into the #Embeddable class because I figured this is where I need to specify the join condition (i.e. between the snpt_id of the snippet_detail and the snpt_id of the snippet table.
Now, the fetch works fine, but when I insert into the snippet_detail I get an hibernate error that says it can't perform the insert because I violate the referential key constraint. In the classes that I have in my original post, the #ManyToOne was within the child class and in that case the insert to the child table would insert a record in the parent snippet table if the record did not already exist in the snippet table.
My parent table class is same as above. The new #Embeddable class and my child classes are modified as:
#Embeddable
public class SnippetDetailPrimaryEntity implements Serializable {
#ManyToOne
#JoinColumn(name = "snpt_id")
private SnippetEntity snippetEntity;
#Column(name = "lang_cd")
private String language;
}
#Entity
#Table(name = "snippet_detail")
public class SnippetDetailEntity implements Serializable {
#EmbeddedId
private SnippetDetailPrimaryEntity snippetDetailPrimaryEntity;
#Column(name = "snpt_type_cd")
private String snippetType;
#Column(name = "snpt_desc")
private String snippetDescription;
#Column(name = "snpt_txt")
private String snippetText;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "cretn_ts")
private Date creationTimeStamp;
#Column(name = "cretn_user_id")
private String creationUserId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updt_ts")
private Date updatedTimeStamp;
#Column(name = "updt_user_id")
private String updatedUserId;
}
So, for a parent child relation where the parent table has a single primary key, child has a composite key and when one of the child's key has a referential constraint back to the parent, this is what worked for me.
Parent
#Entity
#Table(name = "snippet")
public class SnippetEntity implements Serializable{
private static final long serialVersionUID = -3220451853395334879L;
#Id
#Column(name = "snpt_id", nullable=false, updatable=false)
private String snippetId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "cretn_ts")
private Date creationTimeStamp;
#Column(name = "cretn_user_id")
private String creationUserId;
}
Child's composite key as Embeddable:
#Embeddable
public class SnippetDetailPrimaryEntity implements Serializable{
#Column(name = "snpt_id")
private String snippetId;
#Column(name = "lang_cd")
private String language;
}
Child
#Entity
#Table(name = "snippet_detail")
public class SnippetDetailEntity implements Serializable {
private static final long serialVersionUID = -7470223455753164243L;
#EmbeddedId
private SnippetDetailPrimaryEntity snippetDetailPrimaryEntity;
#Column(name = "snpt_type_cd")
private String snippetType;
#Column(name = "snpt_desc")
private String snippetDescription;
#Column(name = "snpt_txt")
private String snippetText;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "cretn_ts")
private Date creationTimeStamp;
#Column(name = "cretn_user_id")
private String creationUserId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updt_ts")
private Date updatedTimeStamp;
#Column(name = "updt_user_id")
private String updatedUserId;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="snpt_id", insertable = false, updatable = false)
private SnippetEntity snippetEntity;
}
I'm trying to insert a record with composite primary key, but at the time of saving a new record I get this message:
e = (org.springframework.orm.jpa.JpaSystemException)
org.springframework.orm.jpa.JpaSystemException: Could not set field
value [POST_INSERT_INDICATOR] value by reflection...
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "produto")
#IdClass(ProdutoId.class)
public class Produto implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_produto")
private Long idProduto;
#Id
#Column(name = "oficina", insertable = false, updatable = false)
private Long idOficina;
#ManyToOne
#JoinColumn(name = "oficina")
private Oficina oficina;
}
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#Data
public class ProdutoId implements Serializable {
public Long idProduto;
public Long idOficina;
}
#Repository
public interface ProdutoRepository extends JpaRepository<Produto, ProdutoId> {}
Has anyone ever seen a bug like this?
To create composite primary key you can refer this example,
#Entity
#Table(name="testuserrole")
public class UserRole{
#EmbeddedId
private UserRoleId id = new UserRoleId();
public UserRoleId getId() {
return id;
}
public void setId(UserRoleId id) {
this.id = id;
}
#Transient
public long getUserId() {
return id.userId;
}
public void setUserId(long userId) {
id.userId=userId;
}
#Transient
public long getRoleId() {
return id.roleId;
}
public void setRoleId(long roleId) {
id.roleId=roleId;
}
}
#Embeddable
class UserRoleId implements Serializable {
#Column(name = "user_id")
public long userId;
#Column(name = "role_id")
public long roleId;
}
I have 5 tables every table has relation one to many with the next table
Project_t -> project_level1_t -> project_level2_t -> project_level3_t -> project_level4_t
I want to user hibernate with these tables
CREATE TABLE project_t
(
projectid serial NOT NULL,
address1 character varying(128),
postcode character varying(7),
city character varying(64),
level_four_name character varying(128),
CONSTRAINT project_t_pkey PRIMARY KEY (projectid),
CONSTRAINT projectcode_unique UNIQUE (projectcode)
)
And project_level1_t
CREATE TABLE project_level1_t
(
projectlevel1id integer NOT NULL DEFAULT nextval('project_level1_t_projectlevel1pk_seq'::regclass),
levelname character varying(256),
projectid integer,
CONSTRAINT project_level1_t_pkey PRIMARY KEY (projectlevel1id),
CONSTRAINT project_level1_t_project_t_fkey FOREIGN KEY (projectid)
REFERENCES project_t (projectid) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
And project_level2_t
CREATE TABLE project_level2_t
(
projectlevel2id integer NOT NULL DEFAULT nextval('project_level2_t_projectlevel2_seq'::regclass),
levelname character varying(256),
projectlevel1id integer,
CONSTRAINT project_level2_t_pkey PRIMARY KEY (projectlevel2id),
CONSTRAINT project_level2_t_projec_level_1_fkey FOREIGN KEY (projectlevel1id)
REFERENCES project_level1_t (projectlevel1id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
And this is the Repository files
package ma.eurnet.mp.tables.model;
import javax.persistence.GenerationType;
#JsonAutoDetect
#Entity
#Table(name = "project_t")
public class ProjectRepository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectRepository() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "projectid")
private Long projectId;
#OneToMany(fetch = FetchType.EAGER, mappedBy="project")
#JsonIgnore
private List<ProjectLevel1Repository> projectlevel1 = new ArrayList<ProjectLevel1Repository>();
public Long getProjectId() {
return projectId;
}
public void setProjectId(Long projectId) {
this.projectId = projectId;
}
public List<ProjectLevel1Repository> getProjectlevel1() {
return projectlevel1;
}
public void setProjectlevel1(List<ProjectLevel1Repository> projectlevel1) {
this.projectlevel1 = projectlevel1;
}
and
package ma.eurnet.mp.tables.model;
#JsonAutoDetect
#Entity
#SequenceGenerator(name = "projectLevel1Sequence", sequenceName = "project_level1_t_projectlevel1pk_seq", allocationSize = 1)
#Table(name="project_level1_t")
public class ProjectLevel1Repository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectLevel1Repository() {
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "projectLevel1Sequence")
#Column(name = "projectlevel1id")
private Long projectLevel1Id;
#ManyToOne
#JoinColumn(name="projectid", referencedColumnName = "projectid")
#JsonIgnore
private ProjectRepository project;
#OneToMany(fetch = FetchType.EAGER, mappedBy="projectlevel1id")
#JsonIgnore
private List<ProjectLevel2Repository> projectlevel2 = new ArrayList<ProjectLevel2Repository>();
public List<ProjectLevel2Repository> getProjectlevel2() {
return projectlevel2;
}
public Long getProjectLevel1Id() {
return projectLevel1Id;
}
public void setProjectLevel1Id(Long projectLevel1Id) {
this.projectLevel1Id = projectLevel1Id;
}
public ProjectRepository getProject() {
return project;
}
public void setProject(ProjectRepository project) {
this.project = project;
}
}
And
package ma.eurnet.mp.tables.model;
import java.io.Serializable;
#JsonAutoDetect
#Entity
#SequenceGenerator(name = "projectLevel2Sequence", sequenceName = "project_level2_t_projectlevel2_seq", allocationSize = 1)
#Table(name="project_level2_t")
public class ProjectLevel2Repository implements Serializable {
private static final long serialVersionUID = 1L;
public ProjectLevel2Repository() {
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "projectLevel2Sequence")
#Column(name = "projectlevel2id")
private Long projectLevel2Id;
#Column(name = "levelname")
private String levelName;
#Column(name = "created_by")
private String createdBy;
#Column(name = "creation_date")
private String creationDate;
#ManyToOne
#JoinColumn(name="projectlevel1id", referencedColumnName = "projectlevel1id")
#JsonIgnore
private ProjectRepository projectlevel1id;
public Long getProjectLevel2Id() {
return projectLevel2Id;
}
public void setProjectLevel2Id(Long projectLevel2Id) {
this.projectLevel2Id = projectLevel2Id;
}
public String getLevelName() {
return levelName;
}
public void setLevelName(String levelName) {
this.levelName = levelName;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public String getCreationDate() {
return creationDate;
}
public void setCreationDate(String creationDate) {
this.creationDate = creationDate;
}
public ProjectRepository getProjectlevel1id() {
return projectlevel1id;
}
public void setProjectlevel1id(ProjectRepository projectlevel1id) {
this.projectlevel1id = projectlevel1id;
}
}
but when I run my application I get this error
org.hibernate.MappingException: Unable to find column with logical name: projectlevel1id in org.hibernate.mapping.Table(project_t) and its related supertables and secondary tables
how can I fix this please
In ProjectLevel2Repository you have a mapping towards ProjectRepository using a #JoinColumn named projectlevel1id which doesn't exist. From what you describe, this should be mapped to ProjectLevel1Repository
#ManyToOne
#JoinColumn(name="projectlevel1id", referencedColumnName = "projectlevel1id")
#JsonIgnore
private ProjectLevel1Repository projectlevel1;