I would have a problem with create a new entity, if it have a join column.
Entity:
#
Entity
#Table(name = "projects")
public class Project {
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy = "increment")
#Column(name = "id_project")
private Long id;
#Column(name = "project_name")
private String name;
#JsonInclude(value = Include.NON_NULL)
#Column(name = "project_language")
private String language;
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
#Column(name = "start_date")
private Date start_date;
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
#Column(name = "end_date")
private Date end_date;
#NotFound(action = NotFoundAction.IGNORE)
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "id_content_manager")
private User contentManager;
if i send this json:
{
"name": "prova3",
"language": "1",
"start_date": "15-04-2018",
"end_date": "26-04-2018"
}
the result are:
Hibernate: insert into projects (id_content_manager, end_date, project_language, project_name, start_date, id_project) values (?, ?, ?, ?, ?, ?)
WARN : org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1452, SQLState: 23000
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Cannot add or update a child row: a foreign key constraint fails (`dipp`.`projects`, CONSTRAINT `projects_user_id_user_fk` FOREIGN KEY (`id_project`) REFERENCES `user` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE)
ERROR: org.hibernate.internal.ExceptionMapperStandardImpl - HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
the method for save the entity:
public void newProject(Project project) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = null;
tx = session.beginTransaction();
if(session != null) {
try {
session.save(project);
tx.commit();
session.close();
}catch(Exception ex) {
session.close();
}
}
}
Someone could help me to solve?
I would need to understand how to pass the parameter "contentManager" as optional in order to pass only the id and then through a find function to retrieve everything and pass it to contentManager
Edit:
The controller:
#RequestMapping(value = "/", method = RequestMethod.POST, consumes = "application/json" , produces = "application/json")
public #ResponseBody ResponseEntity<BaseModel> newProject( #RequestHeader(value="Authorization") String token, #RequestBody Project project, Locale locale) throws ParseException{
if(!SecurityUtil.validateToken(token)) {
return new ResponseEntity<BaseModel>(new BaseModel("error", MessageHandler.returnMessage("invalid_token", locale)), HttpStatus.UNAUTHORIZED);
}
User contentManager = new User();
logger.info(project.getContentManager().getId().toString());
if(project.getContentManager().getId() != null) {
logger.info("have id");
contentManager = userDao.find(project.getContentManager().getId());
}
project.setContentManager(contentManager);
projectDao.newProject(project);
return new ResponseEntity<BaseModel>(new BaseModel("ok", project.getId()), HttpStatus.OK);
}
The problem is with the foreign key projects_user_id_user_fk remove "ON UPDATE CASCADE" and set "ON UPDATE NO ACTION", because when you insert the id it try to update user table and you probably try to save project with empty user.
This is not an answer. Below is the way I have done, this might help you. Before using it I initialize it and set then set it to use in the parent entity.
Icon icon = new Icon();
icon.setIconPath(MiscUtils.getUserIconPath(user));
icon.setUser(user);
user.setIcon(icon);
Related
I have a csv file that has a list of employees and projects information (each employee having multiple projects).
I upload the file, parse the csv and build a parent-child relationship -> Employee and Projects respectively and save it to Database.
Below is my Employee Entity class (I tried the commented part but no luck)
#Entity
#Table(name = "employees")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotNull
private String name;
#NotNull
private String empId;
#NotNull
private String department;
//#OneToMany(fetch = FetchType.LAZY, mappedBy = "transcript", cascade = CascadeType.ALL) //tried didn't work
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee", orphanRemoval = true)
private List<Project> projects;
public Employee(String name, String empId, String department) {
this.name = name;
this.empId = empId;
this.department = department;
}
}
Below is my Project Entity class
#Entity
#Table(name = "projects")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String projectName;
private String projectCode;
private Instant projectStartDate;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
#JoinColumn(name = "employee_id", nullable = false)
#JsonBackReference
private Employee employee;
public Project(String name, String code, Instant time) {
this.projectName = name;
this.projectCode = code;
this.projectStartDate = time;
}
}
This is where I am trying to save my Employee object:
#Transactional
public void uploadEmployees(MultipartFile file) {
try {
//calls csv helper that does all the parsing and brings into Employee model object format
Set<Employess> employees = CSVHelper.csvToEmployess(file.getInputStream(), "2");
employeeRepository.saveAll(employees);
System.out.println("I processed all the records of cdv into java");
} catch (IOException e) {
throw new RuntimeException(e);
}catch (Exception e ){
throw new RuntimeException(e.getMessage());
}
}
This above method throws :
2022-09-11T22:30:08.438-05:00 ERROR 63321 --- [nio-8086-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: null value in column "employee_id" of relation "projects" violates not-null constraint
Detail: Failing row contains (6, p1, 123, 0184-06-08T01:07:47Z, null).
If I change the id generation type to #GeneratedValue(strategy = GenerationType.AUTO) : I get the below exception:
2022-09-12T00:55:09.465-05:00 WARN 73014 --- [nio-8086-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42P01
2022-09-12T00:55:09.465-05:00 ERROR 73014 --- [nio-8086-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: relation "hibernate_sequence" does not exist
Position: 17
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at jdk.proxy2/jdk.proxy2.$Proxy133.saveAll(Unknown Source)
Just before executing saveAll method,I tried looking how my employees list looks like using debugger and it looks as below :
Employee(id=0, name="test", empId="4511504557911789", department="JJ967W"
projects=[
Project(id=0, projectName="p1", projectCode="123", projectStartDate="0184-06-08T01:07:47Z", employee=null),
Project(id=0, projectName="p2", projectCode="345", projectStartDate="0184-06-08T01:07:47Z", employee=null)
]
)
I am thinking employee=null makes sense because it was not saved to DB yet.
Please help me out in what I am missing here that is causing this to break.
Thank you very much for taking time in providng help.
**** UPDATED ****
Adding the part where I am adding parsing CSV and building Employee and Project objects
public static Set<Employee> csvToTranscripts(InputStream is) throws IOException {
try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
CSVParser csvParser = new CSVParser(fileReader,
CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());) {
Set<Employee> employees = new HashSet<>();
List<CSVRecord> csvRecordsList = csvParser.getRecords();
Employee employee = null;
List<String> empIds = new ArrayList<>();
List<Project> projects = null;
//iterate through list and create project list for new emp_id
for(CSVRecord csvRecord : csvRecordsList){
if(employees.isEmpty() || !empIds.contains(csvRecord.get("EMP_ID"))){
employee = new Employee(
csvRecord.get("NAME"),
csvRecord.get("EMP_ID"),
csvRecord.get("DEPARTMENT")
);
empIds.add(csvRecord.get("EMP_ID")); //this is mainly to check for unique emp id
projects = new ArrayList<>();
}
Project project = new Project(csvRecord.get("NAME"),
csvRecord.get("CODE"),
formatToInstant(csvRecord.get("TIME")) );
project.setEmployee(employee);//setting employee to project here
projects.add(project);
employee.setProjects(projects); //setting projects list to employee here
employees.add(employee);
}
return employees;
} catch (IOException e) {
throw new RuntimeException("fail to parse CSV file: " + e.getMessage());
}
}
************ RESOLVED ******************
Thanks everyone for help. Setting employee to project resolved the issue. what a dumb I am !!!
project.setEmployee(employee);
Further to comment by #M.Deinum - declare a method like this in your Employee class and use it to add a project to an employee ensuring the bidirectional relationship is kept in sync
public void addProject(Project project) {
if (projects == null) {
projects = new ArrayList<>();
}
project.setEmployee(this);
projects.add(project);
}
I am thinking employee=null makes sense because it was not saved to DB yet.
This is wrong. If you save an item with bi-directional relationship then you cannot have a case when an orphan Project exists without an Employee. So before calling any CrudRepository.save*() you must make sure that all projects reference some Employee.
Often in such cases when you add projects to employee you do it like:
// method of Employee class
public void addAll(Projects projects) {
for (Project : projects) {
project.setEmployee(this);
}
this.projects.addAll(projects);
}
Code for Module:
#Data
#NoArgsConstructor
#ToString
#Entity(name = "modules")
#Table(name = "modules")
public class Module {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "module_id")
private int moduleId;
#Column(name = "module_name")
private String moduleName;
#Column(name = "module_code")
private String moduleCode;
#Column(name = "moderator_lecturer")
private String moderatorLecturerId;
#Column(name = "secondary_lecturer")
private String secondaryLecturerId;
#OneToMany(mappedBy = "foreignModuleId", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Assessment> assessments;
public void addAssessment(Assessment assessment) {
assessments.add(assessment);
}
}
Code for Assignment
#Data
#NoArgsConstructor
#ToString
#Entity(name = "assessments")
#Table(name = "assessments")
public class Assessment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "assessment_id")
private int assessmentId;
#Enumerated(EnumType.STRING)
#Column(name = "assessment_type")
private AssessmentType assessmentType;
#Column(name = "assessment_weight")
private int assessmentWeight;
#Column(name = "assessment_weeks")
private String weeks;
#Column(name = "assessment_upload_date")
private LocalDate uploadDate;
#Column(name = "assessment_deadline_date")
private LocalDate deadlineDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "assessment_belongsTo_module", referencedColumnName = "module_id")
private Module foreignModuleId;
}
A Module can have many Assessments hence why I chose these annotations.
I firstly extract those data from an excel file and combine them in a list (that is passed later on as an argument called "modules"). The list is of the form:
Module(moduleId=0, moduleName=Programming Principles and Algorithms , moduleCode= CCS1110, moderatorLecturerId=Dr Stamatopoulou, secondaryLecturerId= Dr Efremidis, assessments=[Assessment(assessmentId=0, assessmentType=ASSESSED_LAB, assessmentWeight=35, weeks=00001000000000000, uploadDate=null, deadlineDate=null, foreignModuleId=null), Assessment(assessmentId=0, assessmentType=ASSESSED_LAB, assessmentWeight=65, weeks=00000000000000001, uploadDate=null, deadlineDate=null, foreignModuleId=null)])
Module(moduleId=0, moduleName=Programming Methodology and Design, moduleCode= CCS1115, moderatorLecturerId=Dr Stamatopoulou, secondaryLecturerId= Dr Efremidis, assessments=[Assessment(assessmentId=0, assessmentType=PROJECT, assessmentWeight=35, weeks=00000000000000100, uploadDate=null, deadlineDate=null, foreignModuleId=null), Assessment(assessmentId=0, assessmentType=ASSESSED_LAB, assessmentWeight=65, weeks=00000000000000001, uploadDate=null, deadlineDate=null, foreignModuleId=null)])
Then I upload the list on the database:
#NoArgsConstructor
#Data
public class AppDAOImpl implements AppDAO{
private SessionFactory factory;
public void upload(List<com.project.model.Module> modules) {
Session currentSession = factory.getCurrentSession();
try {
currentSession.beginTransaction();
for(Module module : modules) {
currentSession.save(module);
}
currentSession.getTransaction().commit();
}
finally {
currentSession.close();
factory.close();
}
}
}
When I execute Hibernate create queries of form:
Hibernate: insert into modules (moderator_lecturer, module_code, module_name, secondary_lecturer) values (?, ?, ?, ?)
Hibernate: insert into assessments (assessment_type, assessment_weight, assessment_deadline_date, assessment_belongsTo_module, assessment_upload_date, assessment_weeks) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into assessments (assessment_type, assessment_weight, assessment_deadline_date, assessment_belongsTo_module, assessment_upload_date, assessment_weeks) values (?, ?, ?, ?, ?, ?)
But in the database on the table for Assessments, the field assessment_belongsTo_module is null.
My database has this form:
I have tried a lot of things and cannot fix the problem. I have also read similar threads and still nothing. Maybe there is a problem in the way I have created the fields on each table in the db (e.g. the foreign key)?
Do not use the name Module for a class, say MModule. It is confused with the java.lang.Module.
Create JpaRepository MModuleRepository. Then in a controller, write simply something like
for(MModule module :modules){
moduleRepository.save(module);
}
The problem that was causing this was related to the fact that I did not initialize the attribute "foreignModuleId" in the Assessment class. So when I extract the data from my excel at some point I have the lines:
assessment.setForeignModuleId(module); // I add the module in which the assessment belongs.
module.addAssessment(assessment); // I then add that assessment to the #OneToMany assessments List
I also fixed a stackOverFlow exception that was caused whenever I did operations like retrieving those data from the db, by including this in the Assessment class:
#ToString.Exclude
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "assessment_belongsTo_module", referencedColumnName = "module_id")
private Module foreignModuleId = new Module();
It is very important because Lombok's toString causes a recursive call which then results in the previously mentioned exception.
Tell me how to correctly add a collection consisting of information objects to the database (a table, for example, a family) and so that these objects refer to one user in the user table. At the moment, an error occurs, tried different save options, the error continues:
Request json:
[
{
"name":"luda",
"surname":"Petrova",
"phone":"2353636",
"bus":"black"
},
{
"name":"dima",
"surname":"Petrov",
"phone":"23536336",
"bus":"red"
},
{
"name":"ivan",
"surname":"Petrov",
"phone":"2353",
"bus":"blue"
}
]
RestController :
#RequestMapping(value = { "fam/{id}" },method = RequestMethod.POST)
public User addyfam (#PathVariable Long id, #RequestBody List<FamReq> fammreq){
User usr = userRepo.findById(id).get();
var arr = new ArrayList<Family>();
for(FamReq f : fammreq ) {
arr.add(new Family( f.getName(),f.getSurname(),f.getPhone(),f.getBus()));
}
usr.setFamily(arr);
userRepo.save(usr);
return usr;
}
Entity 1 :
#Entity
#Table(name="usr")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#Column(name="surname")
private String surname;
#OneToOne(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
#JsonManagedReference
private Passport passport;
#OneToMany(
mappedBy = "user",
cascade = {CascadeType.ALL},
orphanRemoval = true
)
private List<Family> family = new ArrayList<>();
/**get/set and constr **/
}
Entity 2:
#Entity
#Table(name="family")
public class Family {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#Column(name="surname")
private String surname;
#Column(name="phone")
private String phone;
#Column(name="bus")
private String bus;
#ManyToOne(
fetch = FetchType.LAZY
)
#MapsId
#NotFound(action = NotFoundAction.IGNORE)
private User user;
/**get/set and constr **/
}
Since the primary key identifier is identical to the foreign key, it is necessary that the family table contains only the secondary key, and the user table contains only its primary key.
UPDATE :
#RequestMapping(value = { "fam/{id}" },method = RequestMethod.POST)
public User addyfam (#PathVariable Long id, #RequestBody List<FamReq>
fammreq){
User us = userRepo.findById(id).get();
var arr = new ArrayList<Family>();
for(FamReq f : fammreq ) {
Family savedFamily = famRepo.save(new Family(f.getName(),f.getSurname(),f.getPhone(),f.getBus()));
arr.add(savedFamily);
Family(f.getName(),f.getSurname(),f.getPhone(),f.getBus()));
}
userRepo.save(arr);
return us;
}
If, in essence, the family indicates this:
#ManyToOne( cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
#JoinColumn(name="user_id", referencedColumnName = "id")
private User user;
Error:
ERROR: NULL in column "user_id" of relationship "family" violates NOT NULL constraint
Details: The error line contains (sdgsgsgsegf, luda, 2353636, Petrova, null, null)
If you indicate this:
#ManyToOne(
fetch = FetchType.LAZY
)
#MapsId
#NotFound(action = NotFoundAction.IGNORE)
private User user;
then
Error:
Error: attempted to assign id from null one-to-one property [com.dbtest.springboot.db_model.Family.user]
UPDATE:
the controller is currently in use :
#RequestMapping(value = { "fam/{id}" },method = RequestMethod.POST)
public User addyfam (#PathVariable Long id, #RequestBody List<FamReq> fammreq){
User usr = userRepo.findById(id).get();
var arr = new ArrayList<Family>();
for(FamReq f : fammreq ) {
arr.add(new Family( f.getName(),f.getSurname(),f.getPhone(),f.getBus()));
}
usr.setFamily(arr);
userRepo.save(usr);
return usr;
}
Repo:
#Repository
public interface UserRepo extends JpaRepository<User, Long >{
User findByname(String name);
void save(ArrayList<Family> fm);
}
full error :
Hibernate: insert into family (bus, name, phone, surname, user_id) values (?, ?, ?, ?, ?)
Hibernate: insert into family (bus, name, phone, surname, user_id) values (?, ?, ?, ?, ?)
Hibernate: insert into family (bus, name, phone, surname, user_id) values (?, ?, ?, ?, ?)
2021-11-14 23:31:06.693 ERROR 13192 --- [nio-9091-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'id' of bean class [java.util.ArrayList]: Could not find field for property during fallback access!] with root cause
org.springframework.beans.NotReadablePropertyException: Invalid property 'id' of bean class [java.util.ArrayList]: Could not find field for property during fallback access!
at org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper.getPropertyValue(DirectFieldAccessFallbackBeanWrapper.java:58) ~[spring-data-commons-2.5.6.jar:2.5.6]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.getId(JpaMetamodelEntityInformation.java:162) ~[spring-data-jpa-2.5.6.jar:2.5.6]
at org.springframework.data.repository.core.support.AbstractEntityInformation.isNew(AbstractEntityInformation.java:46) ~[spring-data-commons-2.5.6.jar:2.5.6]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.isNew(JpaMetamodelEntityInformation.java:246) ~[spring-data-jpa-2.5.6.jar:2.5.6]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:596) ~[spring-data-jpa-2.5.6.jar:2.5.6]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
The problem here is that you try to make a relation by Id but new Family( f.getName(),f.getSurname(),f.getPhone(),f.getBus()) does not assign any Id to your Family.
Create Family Object and store it into a variable.
Save your Family with the help of .save(familyObject) only then your Family is assigned with an Id.
Save your User with a Family attached to it.
Your controller should look like this:
for (FamReq f : fammreq ) {
Family savedFamily = familyRepo.save(new Family(f.getName(),f.getSurname(),f.getPhone(),f.getBus(), us.getId()));
arr.add(savedFamily);
}
us.setFamily(arr);wq21`
userRepo.save(us);
You also should have a FamilyRepository like so:
#Repository
public interface FamilyRepo extends JpaRepository<Family, Long>{
}
NOTE: Do not forget to create injection of this class in your Controller.
NOTE: Never override the .save() method in the Repositories.
Plus you have to insure that your user is found by id otherwise throw an exception that will be caught by Global Controller Advice. Because if you do not your JPA will try to create a relation while referring to a NULL value.
I have a simple select using sqlQuery and I am trying to map it to an entity. I do not understand what the problem is or what can I do about it and I tried multiple sources from this site without any result
function that takes the records
public List<MYTABLE> getRecords(int first, int pageSize, String sortField, Map<String, Object> filters) throws DBEDatabaseException {
try {
EntityManager em = getMyEmOrThrow();
SQLQuery q = em.unwrap(SessionImpl.class).createSQLQuery("SELECT * FROM MYTABLE A where A.status = '1000'");
q.addEntity("A", MYTABLE.class);
q.setFirstResult(first);
q.setMaxResults(pageSize);
List<MYTABLE> results = q.list();
return results;
}catch(RuntimeException e){
throw new MyCustomException("Failure in getting records from table MYTABLE : ", e);
}
```
Entity - **getters and setters and rest of the columns omitted**
#Entity(name = "MYTABLE")
#Table(schema = "MYSCHEMA", name = "MYTABLE")
public class MYTABLE implements Serializable{
#Column(name = "TIMESTAMP", columnDefinition = "TIMESTAMP (6)") // this column is the problem
private Timestamp timestamp;
}
```
THIS DOESN'T WORK AS WELL
#Column(name = "TIMESTAMP", columnDefinition = "TIMESTAMP (6)")
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
[Records in db look like this][1]
[1]: https://i.stack.imgur.com/ahDmJ.png
for formatting date output you should use SimpleDateFormat,
also you could define formatter method to your entity
It is common practice to map the same entity twice or even thrice, every time with a subset of columns needed for processing. I have found that with Hibernate 3.5.1, every time a #ManyToOne or a #OneToMany exists in two entities mapping the same table, the foreign key is created twice. This has no impact on MySQL and SQL Server, but Oracle refuses the second creation statement.
Here is an example:
#Entity
#javax.persistence.SequenceGenerator(name = "SEQ_STORE", sequenceName = "SEQ_ENTITY")
#Table(name = "ENTITIES")
class Entity {
//All columns
//And then.....
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "BRIDGE_TABLE", joinColumns = { #JoinColumn(name = "ENTITY_ID") }, inverseJoinColumns = { #JoinColumn(name = "ROLE_ID") })
#OrderBy("id DESC")
private Set<Role> roles = new HashSet<Roles>();
}
#Entity
#javax.persistence.SequenceGenerator(name = "SEQ_STORE", sequenceName = "SEQ_ENTITY")
#Table(name = "ENTITIES")
class EntityListItem {
//Only a subset of the previous columns
//And then.....
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "BRIDGE_TABLE", joinColumns = { #JoinColumn(name = "ENTITY_ID") }, inverseJoinColumns = { #JoinColumn(name = "ROLE_ID") })
#OrderBy("id DESC")
private Set<Role> roles = new HashSet<Roles>();
}
Currently, Role is designed not to be navigable to Entity (otherwise I guess there will be 4 foreign keys).
Here are the statement being issued by Hibernate:
create table BRIDGE_TABLE (ENTITY_ID number(19,0) not null, ROLE_ID varchar2(60 char) not null, primary key (ENTITY_ID, ROLE_ID)); //Creates the table
alter table BRIDGE_TABLE add constraint FK47CFB9F0B068EF3F foreign key (ENTITY_ID) references ENTITIES;
alter table BRIDGE_TABLE add constraint FK47CFB9F0B068EF3F foreign key (ENTITY_ID) references ENTITIES;
I'm not sure whether this is a Hibernate bug. We cannot currently move to Hibernate 4. Can be this fixed via code or does it need a new Hibernate version?
I have made a workaround:
Add a #ForeignKey annotation with the same FK name to both entities (e.g. #ForeignKey(name = "FK_TO_ENTITY", inverseName = "FK_TO_ROLE"))
Extend LocalSessionFactoryBean like the following:
#override
public void createDatabaseSchema() throws DataAccessException
{
logger.info("Creating database schema for Hibernate SessionFactory");
SessionFactory sessionFactory = getSessionFactory();
final Dialect dialect = ((SessionFactoryImplementor) sessionFactory).getDialect();
final LinkedHashSet<String> sql = new LinkedHashSet<String>();
for (String query : getConfiguration().generateSchemaCreationScript(dialect))
sql.add(query);
HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.execute(new HibernateCallback<Void>()
{
#Override
public Void doInHibernate(Session session) throws SQLException
{
session.doWork(new Work()
{
#Override
public void execute(Connection conn) throws SQLException
{
PhoenixAnnotationSessionFactoryBean.this.executeSchemaScript(conn, sql.toArray(new String[0]));
}
});
return null;
}
});
}
Reason: the #ForeignKey annotation ensures that the FKs will have the same name, hence the SQL statements will be equal each other. The overriden LSFB will store the SQL queries needed to create the schema in a Set so that no duplicate will be allowed.