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;
}
Related
I have two tables one is parent and other one is child. When I am trying to save initially, I am able to insert values in both the tables if values not present in Parent table. But at the time of update/insert the values in child table, it is inserting duplicate values.
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class RuleApi {
Long id;
private String market;
private int modelYear;
private String vehicleLine;
private String vehicleLineName;
private String locale;
private String binding;
private String description;
private String createUser;
private String updateUser;
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class DescriptorSaveRequest {
#Valid
#NotNull
RuleApi rule;
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "MNAVS03_DESCRIPTOR_CONTEXT")
#EntityListeners(AuditingEntityListener.class)
public class DescriptorContext implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Setter(value = AccessLevel.NONE)
#Column(name = "NAVS03_DESCRIPTOR_CONTEXT_K")
private Long id;
#Column(name = "NAVS03_MARKET_N")
private String market;
#Column(name = "NAVS03_MODEL_YEAR_R")
private Integer modelYear;
#Column(name = "NAVS03_VEHICLE_LINE_C")
private String vehicleLine;
#Column(name = "NAVS03_VEHICLE_LINE_N")
private String vehicleLineName;
#Column(name = "NAVS03_LOCALE_N")
private String locale;
#Column(name = "NAVS03_CREATE_USER_C", nullable = false)
private String createUserId;
#CreationTimestamp
#Column(name = "NAVS03_CREATE_S")
private Timestamp createTimestamp;
#Column(name = "NAVS03_LAST_UPDT_USER_C", nullable = false)
private String updateUserId;
#UpdateTimestamp
#Column(name = "NAVS03_LAST_UPDT_S")
private Timestamp updateTimestamp;
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "MNAVS04_DESCRIPTOR_RULE")
#EntityListeners(AuditingEntityListener.class)
public class DescriptorRule implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Setter(value = AccessLevel.NONE)
#Column(name = "NAVS04_DESCRIPTOR_RULE_K")
private Long id;
#JoinColumn(name = "NAVS03_DESCRIPTOR_CONTEXT_K", nullable = false)
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
private DescriptorContext descriptorContextId;
#Column(name = "NAVS04_BINDING_N",
unique = true)
private String binding;
#Column(name = "NAVS04_DESCRIPTOR_RULE_X")
private String description;
#Column(name = "NAVS04_CREATE_USER_C", nullable = false)
private String createUserId;
#CreationTimestamp
#Column(name = "NAVS04_CREATE_S")
private Timestamp createTimestamp;
#Column(name = "NAVS04_LAST_UPDT_USER_C", nullable = false)
private String updateUserId;
#UpdateTimestamp
#Column(name = "NAVS04_LAST_UPDT_S")
private Timestamp updateTimestamp;
}
#ApiOperation(value = "Create/Update Feature Descriptions", notes = "Create/Update a descriptions based on the given input")
#PostMapping("/descriptor/saveFeatures")
public ResponseEntity<BaseBodyResponse<String>> saveFeatureDescriptions(#Valid #RequestBody DescriptorSaveRequest descriptorSaveRequest) throws Exception {
this.descriptorContextService.saveFeatureDescriptions(
this.descriptorContextMapper.mapDescriptorContext(descriptorSaveRequest),
this.descriptorContextMapper.mapDescriptorRule(descriptorSaveRequest)
);
return ResponseEntity.ok(BaseBodyResponse.result("Saved Successfully"));
}
#Service
public class DescriptorContextService {
//SaveFeatureDescriptions
public void saveFeatureDescriptions(DescriptorContext descriptorContext, DescriptorRule descriptorRule) throws Exception {
DescriptorContext descriptorContext1 =
this.descriptorContextRepository.findByMarketAndModelYearAndVehicleLineAndVehicleLineNameAndLocale(
descriptorContext.getMarket(),
descriptorContext.getModelYear(),
descriptorContext.getVehicleLine(),
descriptorContext.getVehicleLineName(),
descriptorContext.getLocale());
if (descriptorContext1 == null) {
// add a new context
descriptorContext1 = descriptorContextRepository.save(DescriptorContext.builder()
.market(descriptorContext.getMarket())
.modelYear(descriptorContext.getModelYear())
.vehicleLine(descriptorContext.getVehicleLine())
.vehicleLineName(descriptorContext.getVehicleLineName())
.locale(descriptorContext.getLocale())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
}
Long contextId = descriptorContext1.getId();
List<DescriptorRule> rule = this.descriptorRuleRepository.findByDescriptorContextId(contextId);
if (rule.size() == 0) {
// add a new rule
this.descriptorRuleRepository.save(DescriptorRule.builder()
.descriptorContextId(descriptorContext1)
.binding(descriptorRule.getBinding())
.description(descriptorRule.getDescription())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
} else {
// update a existing rule
for (DescriptorRule descriptorRule1 : rule) {
if (descriptorRule1.getBinding().equals(descriptorRule.getBinding())) {
descriptorRule1.setDescription(descriptorRule.getDescription());
descriptorRule1.setupdateUserId(descriptorRule.getupdateUserId());
this.descriptorRuleRepository.save(descriptorRule1);
} else {
this.descriptorRuleRepository.save(DescriptorRule.builder()
.descriptorContextId(descriptorContext1)
.binding(descriptorRule.getBinding())
.description(descriptorRule.getDescription())
.createUserId(descriptorContext.getCreateUserId())
.updateUserId(descriptorContext.getUpdateUserId())
.build());
}
}
}
}
}
}
#Component
public class DescriptorContextMapper {
public DescriptorContext mapDescriptorContext(DescriptorSaveRequest descriptorSaveRequest) {
return DescriptorContext.builder()
.market(descriptorSaveRequest.getRule().getMarket())
.vehicleLine(descriptorSaveRequest.getRule().getVehicleLine())
.vehicleLineName(descriptorSaveRequest.getRule().getVehicleLineName())
.modelYear(descriptorSaveRequest.getRule().getModelYear())
.locale(descriptorSaveRequest.getRule().getLocale())
.createUserId(descriptorSaveRequest.getRule().getCreateUser())
.updateUserId(descriptorSaveRequest.getRule().getUpdateUser())
.build();
}
public DescriptorRule mapDescriptorRule(DescriptorSaveRequest descriptorSaveRequest) {
return DescriptorRule.builder()
.id(descriptorSaveRequest.getRule().getId())
.binding(descriptorSaveRequest.getRule().getBinding())
.description(descriptorSaveRequest.getRule().getDescription())
.createUserId(descriptorSaveRequest.getRule().getCreateUser())
.updateUserId(descriptorSaveRequest.getRule().getUpdateUser())
.build();
}
}
{
"rule": {
"binding": "5003",
"description": "Test new 5003-2023 Escape",
"locale": "fr_CA",
"market": "WANAC",
"modelYear": 2023,
"vehicleLine": "TMC",
"vehicleLineName": "Escape",
"createUser": "rdongre",
"updateUser": "rdongre"
}
}
If I am passing this request and values are not present in both the tables then it should insert the values in both the tables which is working as expected with above code. But at the time of update it is going inside the loop and inserting duplicate values. I am trying to update DESCRIPTION in child table if BINDING is present if not it should insert BINDING plus DESCRIPTION
I fixed this by separating Save and Update methods. Thanks to all.
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;
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
I am confused about how to save entry in db with column's join. I have #Entity bellow
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
#Entity
#Table(name = "psc_users")
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 8885916014620036457L;
#Id
private static final String SEQUENCE_NAME = "psc_users_user_id_seq";
#Id
#GeneratedValue(generator = "UseExistingOrGenerateIdGenerator",
strategy = GenerationType.SEQUENCE)
#GenericGenerator(name = "UseExistingOrGenerateIdGenerator",
strategy = "com.psc.util.UseExistingOrGenerateIdGenerator",
parameters = {
#org.hibernate.annotations.Parameter(name = "sequence", value = SEQUENCE_NAME)
}
)
#Column(name = "USER_ID")
private Long userId;
#Column(name = "DEF", length = 30)
private String def;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "DEL_DATE")
private Date delDate;
#Column(name = "DISPLAY_DEF", length = 60)
private String displayDef;
#Column(name = "EMAIL", length = 60)
private String email;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "NAVI_DATE")
private Date naviDate;
#Column(name = "NAVI_USER")
private String naviUser;
#Column(name = "PHONE", length = 30)
private String phone;
#Column(name = "PWD", length = 40)
private String pwd;
//bi-directional many-to-one association to Branch
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "BRNC_BRNC_ID", nullable = false)
private Branch pscBranch;
public Long getBrncBrncId() {
return brncBrncId;
}
public void setBrncBrncId(Long brncBrncId) {
this.brncBrncId = brncBrncId;
}
#Column(name = "BRNC_BRNC_ID", insertable = false, updatable = false)
private Long brncBrncId;
//bi-directional many-to-one association to User
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "CURATOR_USER_ID")
private User pscUser;
public Long getCuratorUserId() {
return curatorUserId;
}
public void setCuratorUserId(Long curatorUserId) {
this.curatorUserId = curatorUserId;
}
#Column(name = "CURATOR_USER_ID", insertable = false, updatable = false)
private Long curatorUserId;
public User() {
}
public Long getUserId() {
return this.userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getDef() {
return this.def;
}
public void setDef(String def) {
this.def = def;
}
public Date getDelDate() {
return this.delDate;
}
public void setDelDate(Date delDate) {
this.delDate = delDate;
}
public String getDisplayDef() {
return this.displayDef;
}
public void setDisplayDef(String displayDef) {
this.displayDef = displayDef;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getNaviDate() {
return this.naviDate;
}
public void setNaviDate(Date naviDate) {
this.naviDate = naviDate;
}
public String getNaviUser() {
return this.naviUser;
}
public void setNaviUser(String naviUser) {
this.naviUser = naviUser;
}
public String getPhone() {
return this.phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPwd() {
return this.pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Branch getPscBranch() {
return this.pscBranch;
}
public void setPscBranch(Branch pscBranch) {
this.pscBranch = pscBranch;
}
public User getPscUser() {
return this.pscUser;
}
public void setPscUser(User pscUser) {
this.pscUser = pscUser;
}
}
if I save User instance without field pscUser (here null) but there is valid CuratorUserId with correct value I end up in a situation with empty CuratorUserId in db. If you look at code then you will see these bound fields.
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "CURATOR_USER_ID")
private User pscUser;
#Column(name = "CURATOR_USER_ID", insertable = false, updatable = false)
private Long curatorUserId;
code to save user
repositoryUser.save(user);
this i see in debugger
this i see in database after saving my user.
sorry for my stupid question but I come across on a different behavior, there is code in my project which behaves in another manner. I don't want to search actual another user(curator) for saving my user, because of overhead on query
The #Column annotation on the curetorUserId field has properties
insertable=false and updatable=false, which means that its value is ignored during inserts and updates.
You can either change these properties to true (but it can break your application in some other places) or just fill in pscUser field using EntityManager.getReference, which just creates a proxy and doesn't actualy produce a query to the database.
Your mapping should look like the below:
#XmlRootElement
#XmlAccessorType(value = XmlAccessType.FIELD)
#Entity
#Table(name = "psc_users")
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 8885916014620036457L;
#Id
private static final String SEQUENCE_NAME = "psc_users_user_id_seq";
#Id
#GeneratedValue(generator = "UseExistingOrGenerateIdGenerator",
strategy = GenerationType.SEQUENCE)
#GenericGenerator(name = "UseExistingOrGenerateIdGenerator",
strategy = "com.psc.util.UseExistingOrGenerateIdGenerator",
parameters = {
#org.hibernate.annotations.Parameter(name = "sequence", value = SEQUENCE_NAME)
}
)
#Column(name = "USER_ID")
private Long userId;
#Column(name = "DEF", length = 30)
private String def;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "DEL_DATE")
private Date delDate;
#Column(name = "DISPLAY_DEF", length = 60)
private String displayDef;
#Column(name = "EMAIL", length = 60)
private String email;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "NAVI_DATE")
private Date naviDate;
#Column(name = "NAVI_USER")
private String naviUser;
#Column(name = "PHONE", length = 30)
private String phone;
#Column(name = "PWD", length = 40)
private String pwd;
//bi-directional many-to-one association to Branch
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "BRNC_BRNC_ID", nullable = false)
private Branch pscBranch;
//bi-directional many-to-one association to User
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "CURATOR_USER_ID")
private User pscUser;
public User() {
}
}
You need to think in terms of objects. The FK will only be set in the database if you set the pscUser reference to an instance of a User. If this is an existing User then you need to set a reference to the existing persistent entity.
Real answer is that I have two points for saving and updating my entity. Please see this Hibernate: Where do insertable = false, updatable = false belong in composite primary key constellations involving foreign keys?
I have two entity class Category and Events.I need to join both the tables and fetch all records which matching the given condition
My sql query for this
SELECT * FROM category c inner join `events` e on e.category_i=c.category_id where c.parent_category_id=1;
How i can convert this sql query to hql and fetch the data ? I tried below but not getting the result ? Am very new to hibernate
Events entity class for hibernate mapping
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
/**
* The persistent class for the user database table.
*
*/
#Entity
#Table(name = "events")
public class Events implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "event_id")
private int eventId;
#Column(name = "event_name")
private String eventName;
#Column(name = "event_description")
private String eventDescription;
#Column(name = "category_i")
private Integer categoryI;
public Integer getCategoryI() {
return categoryI;
}
public void setCategoryI(Integer categoryI) {
this.categoryI = categoryI;
}
#Column(name = "is_trending_event")
private Integer isTrendingEvent;
#Column(name = "image_url")
private String imageUrl;
private Integer status;
#Column(name = "created_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date createdDate;
#Column(name = "last_updated_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastUpdatedDate;
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Date getLastUpdatedDate() {
return lastUpdatedDate;
}
public void setLastUpdatedDate(Date lastUpdatedDate) {
this.lastUpdatedDate = lastUpdatedDate;
}
public int getEventId() {
return eventId;
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public String getEventDescription() {
return eventDescription;
}
public void setEventDescription(String eventDescription) {
this.eventDescription = eventDescription;
}
public Integer getIsTrendingEvent() {
return isTrendingEvent;
}
public void setIsTrendingEvent(Integer isTrendingEvent) {
this.isTrendingEvent = isTrendingEvent;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
Category entity
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
/**
* The persistent class for the user database table.
*
*/
#Entity
#Table(name = "category")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private int categoryId;
#Column(name = "category_name")
private String categoryName;
#Column(name = "parent_category_id")
private Integer parentCategoryId;
#Column(name = "created_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date createdDate;
#Column(name = "last_updated_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastUpdatedDate;
#ManyToOne
#JoinTable(name="events", joinColumns = #JoinColumn(name="category_i"))
private Events events;
public int getCategoryId() {
return categoryId;
}
public void setCategoryId(int categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Integer getParentCategoryId() {
return parentCategoryId;
}
public void setParentCategoryId(Integer parentCategoryId) {
this.parentCategoryId = parentCategoryId;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Date getLastUpdatedDate() {
return lastUpdatedDate;
}
public void setLastUpdatedDate(Date lastUpdatedDate) {
this.lastUpdatedDate = lastUpdatedDate;
}
}
Fetch category method
public List<Object[]> getCategoryList(int id) throws SQLException, ClassNotFoundException, IOException {
List<Object[]> groupList = null;
try {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("select e from Category e inner join e.events where e.parentCategoryId=1");
//query.setParameter("id", id);
groupList = query.list();
} catch (Exception e) {
}
return groupList;
}
You need to think in terms of Java objects when using ORM tools.
From your question I think the query that you're trying to write will look something like:
public List<Category> getCategoryList(int id) {
List<Category> groupList;
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("select c from Category c join fetch c.events where c.parentCategory.categoryId = 1");
//query.setParameter("id", id);
groupList = query.list();
return groupList;
}
One of the benefits of using an ORM is that it works out the full join query for you.
For this to work you need to update your class model as follows:
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
#Entity
#Table(name = "events")
public class Event implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "event_id")
private int eventId;
#Column(name = "event_name")
private String eventName;
#Column(name = "event_description")
private String eventDescription;
#ManyToOne
#JoinColumn(name = "category_i")
private Category category;
#Column(name = "is_trending_event")
private Integer isTrendingEvent;
#Column(name = "image_url")
private String imageUrl;
private Integer status;
#Column(name = "created_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date createdDate;
#Column(name = "last_updated_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastUpdatedDate;
...
}
and
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
#Entity
#Table(name = "category")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private int categoryId;
#Column(name = "category_name")
private String categoryName;
#ManyToOne
#JoinColumn(name="parent_category_id")
private Category parentCategory;
#Column(name = "created_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date createdDate;
#Column(name = "last_updated_date")
#Temporal(javax.persistence.TemporalType.DATE)
private Date lastUpdatedDate;
#OneToMany(mappedBy="category")
private List<Event> events;
...
}
Hibernate is about mapping objects and the relations, however you are mapping simple id fields.
In your Events class you have the followingL
#Entity
#Table(name = "events")
public class Events implements Serializable {
#Column(name = "category_i")
private Integer categoryI;
}
However it should be a Category instead of an Integer.
#Entity
#Table(name = "events")
public class Events implements Serializable {
#ManyToOne
#Column(name = "category_i")
private Category category;
}
Then in your Category you should add the mappedBy field to the #ManyToOne on the events field and remove the #JoinColumn.
#Entity
#Table(name = "category")
public class Category implements Serializable {
#OneToMany(mappedBy="category")
private Events events;
}
The same applies to the parentCategoryId of the Category class.
Now that you have your mapping corrected you should be able to write the query as you wanted to.
This query should do the job:
from Category as c
inner join c.events as e
where c.parentCategoryId = 1
Plus you seem to have a typo (missing "d" at the end) here:
#JoinColumn(name="category_i"))
Ty this below code
public List<Object[]> getCategoryList(int id) throws SQLException, ClassNotFoundException, IOException {
Session session = sessionFactory.getCurrentSession();
return session.createCriteria(Catagory.class)
.setFetchMode("events", FetchMode.JOIN)
.add(Restrictions.eq("parentCatagoryId", 1))
.list();
}
Hope this stuff works.