JPA Spring saving entity to a different name in MariaDB - java

The first code block is the entity and the second code saves the tag to the database.
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String tagName;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "tags")
private Set<Board> boards = new HashSet<>();
}
public void getTagList(String tagName) {
Tag tag = new Tag();
tag.setTagName(tagName);
tagRepository.save(tag);
}
Whenever I send over the tagName, I get an error saying
*java.sql.SQLSyntaxErrorException: (conn=564) Unknown column 'tag_name' in 'field list'
I don't have 'tag_name' anywhere in my code and I'm not sure why JPA is trying to save it with a slightly different name.
I added a column called tag_name in the database and it seems to work and save the data into tag_name.

You can match the DB column name with your field like this.
#Column(name="tag_name")
private String tagName;

Related

Hibernate Unidirectional OneToMany Not Working with composite id

I've been bashing my head on my keyboard for two days trying to figure this out...
Some background: We have a data model set up with a Perl code base that runs straight native SQL statements to the database via ODBC. For certain reasons, we decided to rewrite the code in Java... I thought it would be a good idea to use Hibernate to define all of the mappings. We don't want to edit the data model.
For simplicity sake, I can express the problem with only part of our data model. We have the entities "Job","JobDatabase" and "JobTable".
Job has a PK of job_name. Database has a PK of job_name,name. Table has a PK of job_name,src_database_name,name. As you may expect, Job has a OneToMany relationship with JobDatabase, and Database has a OneToMany with JobTable.
For purposes of this test, I'm starting with empty tables and trying to create some sample data. I can insert a Job and a JobDatabase, but when I try to insert the JobTable, Hibernate throws an error. Or more accurately, that is where it complains. It doesn't start executing my code because it detects the mapping error. However, if I remove the association between JobDatabase and JobTable, it will insert all Job and JobDatabase records correctly with no errors.
Sample Classes (all fields have getters/setters... there are also many other fields):
#Entity
#Table(name="Job")
public class Job implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "job_name", referencedColumnName = "job_name")
private Set<JobDatabase> databases;
}
#Entity
#Table(name="JobDatabase")
public class JobDatabase implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="name",nullable = false)
private String name;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "job_name", referencedColumnName = "job_name"),
#JoinColumn(name = "name", referencedColumnName = "src_database_name")
})
private Set<JobTable> tables;
}
#Entity
#Table(name="JobTable")
public class JobTable implements Serializable{
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="src_database_name",nullable = false)
private String srcDatabaseName;
#Id
#Column(name="name",nullable = false)
private String name;
}
The error:
Exception in thread "main" org.hibernate.MappingException: Unable to find column with logical name: src_database_name in JobDatabase
I keep getting this error. I do not understand why it is looking for the referenced column in the entity "owning" the mapping. src_database_name does indeed only exist in JobTable - it is referred to as "name" in JobDatabase. JobTable also has a "name" field, but it refers to the name of the Table.
You need to have src_database_name column in your JobDatabase table. Or you can change src_database_name to other column name.
For composite key reference column must be present in your source table.

Hibernate one to many relationship annotation

I have problem with settings relationship one to many. I want to create relationship between FindingAid and FindingAidVersion. I tried example in Hibernate documentation and many examples in the Internet but I don't know what is wrong.
FindingAid.java
Public class FindingAid implements Serializable {
private String id;
....
#OneToMany
#JoinColumn(name="id")
private Set<FindingAidVersion> listVersion = new HashSet<FindingAidVersion();
...... generate getter and setter .....
}
FindingAidVersion.java
Public class FindingAidVersion implements Serializable {
private String id;
private Date closeDate;
private FindingAid findingAid;
.......
#ManyToOne
#JoinColumn(name = "id", nullable = false)
public FindingAid getFindingAid() {
return findingAid;
}
...... generate getter and setter .....
}
Application code is:
FindingAid data = new FindingAid();
data.setCreateDate(new Date());
data.setName("daniel");
FindingAidVersion verse = new FindingAidVersion();
verse.setCloseDate(new Date());
verse.setIsClose(false);
data.getListVersion().add(verse);
this.getSession().save(data);
this.getTx().commit();
Error is:
Repeated column in mapping for entity: cz.tacr.elza.api.model.FindingAidVersion column: id (should be mapped with insert="false" update="false")
I know that problem is in annotation #JoinColumn but I am lost.
Thanks for your suggestions.
Have you tried to do what the error message suggest ?
#JoinColumn(name = "id", nullable = false, insert=false, update=false)
And in FindindAid for the listVersion attribute try
#OneToMany(mappedBy="findingAid")
Look at your new error:
foreign key constraint "fk_3o68boae9f3oamcm6dfy77tfw" cannot be implemented Detail: Key columns "findingaid" and "id" are of incompatible types: bytea and character varying
On one table (finding_aid_version ) you have "findingAid bytea" and on the other (finding_aid) "id varchar(255)",

How to correctly add records to jpa onetomany join table

I'm developing a filing system where I have 3 tables. PROJECTS table consists of projectid, project name and other details (see below). This is an existing class and populated schema and I do not want to modify this part of the application if possible.
Folders table (Called ProjectClassification) consists of folderid and foldername and is the owning side of a unidirectional onetomany relationship.
Project_Folders is a join table. I'm using JPA 2.0 (EclipseLink) and JSF 2.0 as my web framework.
My basic problem is I can't add duplicate records to the join table using a merge operation. MERGE is good for adding records until the owning key already exists, after which point it will only update the join table. I know this is the way it's supposed to work but I need to add new records even if there's a duplicate of the owning key. This will allow me to store different projects in the same folder.
I've looked through some other questions here such as:
onetomany unidirectional with jointable setup using jpa
This says what is needed to add one entity to the other in a join table but i need to know more about how to correctly persist or merge the added entity to the database.
The folder entity class:
#Entity
#Table(name = "PROJECTCLASSIFICATIONS")
public class ProjectClassifications implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int proclassid;
private int projectid;
private String classification;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "PROJECT_CLASSF_JOIN",
joinColumns = #JoinColumn(name = "proclassid", referencedColumnName = "proclassid"),
inverseJoinColumns = #JoinColumn(name = "projectid", referencedColumnName = "projectid", unique = true))
private Collection<Projects> projects;
public ProjectClassifications() {
}
public ProjectClassifications(String classification) {
this.classification = classification;
}
public ProjectClassifications(int proclassid, int projectid) {
this.proclassid = proclassid;
projects = new ArrayList<Projects>();
}
public ProjectClassifications(Projects newProject) {
projects = new ArrayList<Projects>();
}
public void addProject(Projects newProject) {
if(!getProjects().contains(newProject))
getProjects().add(newProject);
}
....
....
The Project entity class is a pre existing code and I do not want to modify at all if possible:
#Entity
#Table(name = "PROJECTS")
public class Projects {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int projectid;
private String projectName;
private String projectDescription;
#Temporal(javax.persistence.TemporalType.DATE)
private Date startDate;
#Temporal(javax.persistence.TemporalType.DATE)
private Date endDate;
private String commnts;
// foreign keys to parent tables
private int fk_countryid;
private int fk_companyid;
private int fk_employeeid;
#ManyToOne(optional = true)
#JoinColumn(name = "countryid")
private Country country;
....
....
I then use two html select lists to select values for projectid and proclassid which call the following methoid using a JSF managed bean:
public String makeProClassRecord() {
newProClass = new ProjectClassifications(proclassid, projectid);
newProject = proServ.findByProjectId(projectid);
newProClass.addProject(newProject);
facade.update(newProClass);
//facade.save(newProClass);
return showProclass();
}
My questions are:
1) Is MERGE the correct operation used to add records into a join table?
2) Is there a way to add records that contain duplicate keys (foreign keys represented as new records in the join table) using MERGE?
3) Should PERSIST be used to achieve question 2?
4) Would it be better to create an entity for the join table itself and simply use a PERSIST method to insert the records?
Many thanks
So I solved this myself a couple of weeks ago and thought of sharing the answer. Instead of doing merge or persist operations on any of the target entities, I created a Join table and unidirectional OneToMany relationship from the Project entity to the below ProjectFileSystem join table entity and simply did the persist operation using that entity. I need to add duplicate folders for different projects (or store many projects under a single folder item) so it seems more efficient to do the CRUD operations in the actual join table entity rather than from the target entity. Hope this helps:
#Entity
#Table(name = "PROFOLDERSYS_JOIN")
public class ProjectFileSystem implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int foldersysid;
private int proclassid;
private int projectid;
private String projectName;
private String folderName;
public ProjectFileSystem() {
}
public ProjectFileSystem(int proclassid, int projectid,
String projectName, String folderName) {
this.proclassid = proclassid;
this.projectid = projectid;
this.projectName = projectName;
this.folderName = folderName;
}
// getters and setters
}
The method in the bean would be:
public String makeProSys() {
newProSys = new ProjectFileSystem(proclassid, projectid, classification, projectName);
newProject = proServ.findByProjectId(projectid);
projectName = newProject.getProjectName();
newProSys.setProjectName(projectName);
newProClass = facade.findByContactId(proclassid);
classification = newProClass.getClassification();
newProSys.setFolderName(classification);
profilFacade.save(newProSys);
return showProSys();
}

org.hibernate.TransientObjectException if any many-to-one fields are null (or not selected in form)

I am using jpa with play framework.I have an entity JobseekerDetails
#Entity
public class JobseekerDetails {
#Id
#Column(name = "jobseekerDetails_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long jobseekerDetails_id;
#ManyToOne
#JoinColumn(name = "basicEducation_id")
private JobseekerFormBasicEducation basicEducation;
#ManyToOne
#JoinColumn(name = "masterEducation_id")
private JobseekerFormMasterEducation masterEducation;
#ManyToOne
#JoinColumn(name = "doctrateEducation_id")
private JobseekerFormDoctrateEducation doctrateEducation;
#ElementCollection
private List<String> certificateName =new ArrayList<String>();
#Column(length = 3000)
private String resume;
private Long experience;
private String skills;
private String resumePath;
#ManyToOne
#JoinColumn(name = "industry_id")
private JobseekerFormIndustry industry;
#ManyToOne
#JoinColumn(name = "functionalArea_id")
private JobseekerFormFunctionalArea functionalArea;
}
which have a many-to-one relation with other entities like JobseekerFormFunctionalArea , JobseekerFormIndustry etc.These entities have fixed value which is already saved in the database.
When JobseekerDetails is saved all its details should be saved with corresponding manytoone relation ids but donot save to Entity JobseekerFormFunctionalArea and JobseekerFormIndustry as they are predefined
My problem is that when i save(through my form) all the manytoone relation fields ids in JobseekerDetails it is saved properly but when submit my form without selecting any value in any manytoone relation fields For ex if i dont select anything in my fuctionalArea_id field it gives the below exception
org.hibernate.TransientObjectException:object references an unsaved transient instance - save the transient instance before flushing
If I select all the fields the details are saved but if I dint select anyone field which is mapped manytoone in my model then it gives above exception
But jpa automatically set nullable=true then why this happend
I have searched a bit and found that this problem can be solved by adding cascade .I added cacade type Merge but getting the above same exception.
I also tryed setting nullable=true but getting same error
On setting cascade = CascadeType.ALL and cascade = CascadeType.PERSIST I am getting below exception
PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist:
Any help would be appreciated
When you don't select any 'basicEducation' in the form and you are saving form then there is new object there with empty id. So you have:
jobseekerDetails.basicEducation = new JobseekerFormBasicEducation ()
This causes TransientObjectException
To avoid it you have to set
jobseekerDetails.basicEducation=null
before saving.

Why is Hibernate not filling this foreign key column

This problem seems occur often, but I couldn't find a working solution for my case. Problem is that Hibernate leaves the foreign key of one foreign key column empty (null). Strange thing is that I use the same setup of these two affected tables in another program and it works fine. Only difference is that I now added 2 other tables.
I checked the MySQL output (via show_sql option) and Hibernate inserts the parent table before the child. So the key should be there.
Parent:
public class Page {
#Id
#GeneratedValue
#Column(name="page_id")
private Integer id;
//****** THIS IS THE CHILD
#OneToMany(orphanRemoval=true, mappedBy="pageId", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Tag> tag = new HashSet<Tag>();
//****** THESE ARE THE NEW TABLES
#OneToOne(cascade=CascadeType.ALL)
private Video video;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="creator_id")
private Creator creator;
Child:
public class Tag {
#Id
#GeneratedValue
private Integer id;
#Index(name = "tag")
#Column
private String tag;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="page_id")
private Page pageId;
How it is saved (saveOrUpdate is necessary):
public static void save(SessionFactory sessionFactory, Page page) {
Session session = sessionFactory.openSession();
session.beginTransaction();
session.saveOrUpdate(page);
session.getTransaction().commit();
session.close();
}
Every suggestion are highly appreciated!
Are you managing both sides of the association? Meaning that you add the Tag to the Set<Tag> in Page and set the Page field on the Tag?
Before passing Page to the save method you should be managing the relationship as follows:
Page page = new Page();
Tag tag = new Tag();
//managing the both sides of the relationship
tag.setPage(page); //Setting Tags page field
page.getTags().add(tag); //Adding tag to the `Set<Tag>`

Categories