I am trying to run sql scripts on startup of the webapp using hibernate.hbm2ddl.import_files, but this doesn't seem to be working. I am using the following in my persistence.properties:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost/rays_rentals?createDatabaseIfNotExist=true
dataSource.username=root
dataSource.password=
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create
hibernate.hbm2ddl.import_files=bikes.sql
My bikes.sql file is saved in the same place as my properties file.
Here is my sql file:
INSERT INTO `bikes` (`id`, `brand`, `model`) VALUES (1, 'Giant', 'Propel Advanced 0');
Here is my Bike model:
package com.BrightFuture.RaysRentalSystem.bikes;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Proxy;
#Entity
#Proxy(lazy = false)
#Table(name = "bikes")
public class Bike {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy="bike", cascade=CascadeType.ALL)
private List<BikeRecord> bikeRecords = new ArrayList<BikeRecord>();
#Column(name="brand", nullable=false)
private String brand;
#Column(name="model", nullable=false)
private String model;
}
Thanks.
I solved this issue. everything in my question is right.. i was just missing the configuration for it in my JpaConfig
Please modify your properties file with below attribute:
hibernate.hbm2ddl.auto=update
Related
I have created a pretty small and simple Spring Boot app using the Oracle database and some JPA queries.
This is the code snippet which is not returning data, which is actually exists in database.
letterRecipientNonOas = letterRecipientNonOasRepository
.findById(Long.valueOf(letterRecipientDTO.getNonOas().getId()))
.orElseThrow(() -> new EntityNotFoundException(LetterRecipientNonOas.class,
Constant.MESSAGE_ENTITY_NOT_FOUND));
here findById is returning empty result set.
this is my repository
package com.care.document.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.care.document.model.LetterRecipientNonOas;
/**
* The Interface LetterRecipientNonOasRepository.
*/
#Repository
public interface LetterRecipientNonOasRepository extends PagingAndSortingRepository<LetterRecipientNonOas, Long> {
Optional<LetterRecipientNonOas> findByLetterId(Long id);
Optional<LetterRecipientNonOas> findByTitleIgnoreCase(String title);
List<LetterRecipientNonOas> findByTitleContainingIgnoreCase(String title);
List<LetterRecipientNonOas> findAllByTitleIgnoreCaseAndIdNot(String title, Long recipientId);
List<LetterRecipientNonOas> findAllByIdAndLetterId(long id, long letterId);
}
and this is my model class:
package com.care.document.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import org.springframework.lang.Nullable;
import com.care.admin.model.BaseEntity;
import com.care.admin.util.CommonUtil;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Entity
#Table(name = "letter_recipient_non_oas")
public class LetterRecipientNonOas extends BaseEntity implements Serializable {
#Id
Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "letter_id")
Letter letter;
Integer recipientType; // Action/Info
//byte recipientSubType; // Internal/External/NonOAS
byte recipientCategory; //Internal/External
int orderNo;
String title;
#Nullable
String remarks;
String address;
#PrePersist
private void prePersist() {
this.id = CommonUtil.generateID(this.atRegion);
}
}
I tested, tried different ways but of no use.
There are a couple of scenarios how one might get this impression:
You are looking at the wrong database.
The data isn't there yet when you try to load it, but is when you check.
JPAs caches are known to create such scenarios rather efficiently.
The data looks a little different than you think. This could be caused by invisible or easy to miss content like spaces or even control characters.
You check the database within the transaction that created the data or with a session that allows dirty reads and the insert that created the data wasn't committed yet.
I'm having issues unit testing the DbRequest controller. I have one unit test working, but I'm unable to achieve a unit test for the DBRequest controller GET mappings which does a database lookup using hibernate. I' have an H2 in memory database created for the junit tests.
I've tried a variety of different setups, and nothing seems to work correctly.
Edited the below, I'm getting a NullPointer,
java.lang.NullPointerException
at com.lmig.informaticaservice.api.DBcontroltest.saveTest(DBcontroltest.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Here is the edited test.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DBcontroltest {
#Autowired
DbRequest dbRequest;
#Autowired
ConnectionRequestRepository connectionRequestRepository;
private MockMvc mockMvc;
// #Autowired
//private TestEntityManager entityManager;
#Test
public void saveTest() throws Exception {
ConnectionRequest connectionRequest = new ConnectionRequest((long) 1, "test");
connectionRequestRepository.save(connectionRequest);
System.out.println(connectionRequestRepository.findAll().toString());
mockMvc.perform(get("/api/selectDB/{connectionId}" ,1))
.andExpect(status().isOk());
}
}
Typical JPA repository
package com.test.models;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ConnectionRequestRepository extends JpaRepository<ConnectionRequest, Long> {
}
Here is my controller.
package com.test.api;
import com.models.ConnectionRequest;
import com.test.models.ConnectionRequestRepository;
import java.util.List;
import javax.validation.Valid;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Data
#RestController
#RequestMapping("/api/")
public class DbRequest {
#Autowired
private ConnectionRequestRepository connectionRequestRepository;
private ConnectionRequest connectionRequest;
#GetMapping("/selectDB")
public List<ConnectionRequest> getAllRequests() {
return connectionRequestRepository.findAll();
}
#GetMapping("/selectDB/{connectionId}")
public ResponseEntity<ConnectionRequest> getRequestById(#PathVariable("connectionId") Long connectionId) throws Exception {
ConnectionRequest connectionRequest = connectionRequestRepository.findById(connectionId)
.orElseThrow(() -> new Exception("Connection Request " + connectionId + " not found"));
return ResponseEntity.ok().body(connectionRequest);
}
}
Here is the model for the database.
package com.testing.models;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
#Data
#Entity
#Table(name = "connrequest", schema = "testschema")
#AllArgsConstructor
#NoArgsConstructor
#EntityListeners(AuditingEntityListener.class)
public class ConnectionRequest {
#Id
#Column(name = "connection_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long connectionId;
#Column(name = "requestor", nullable = false)
private String requestor;
}
It looks like the on of the annotations on the PK of ConnectionRequest is the problem.
The annotation #GeneratedValue tells JPA that it needs to determine the value, so any provided value for the ID will be actively discarded. From the docs
Indicates that the persistence provider must assign primary keys for the entity using a database identity column.
To fix this try either removing that annotation, so then you must always provide an ID, or alternatively, after saving the entity in your test, get the ID that is assigned and call connectionRequestRepository.getOne() with that ID.
I'm continuing the development of a system that uses the React JavaScript library (and related stuff) on the front end and Spring Data REST, Hibernate, PostgreSQL and related stuff on the back end.
This system will be used by people who may own one or more companies and their clients. This means that most/all model objects will have a reference to the Company(ies) that they belong to. Also, company owners will have a few Employees that will have higher level access on this system (or these will be the owners themselves).
I need to implement a functionality where, when a company is inserted in the database, an employee is inserted as well. Also, if one fails, both must fail. Because of how the model was set up, I'm sending an Employee object to be saved, and, within it, the new Company, like this (using Axios):
employee: {
// ...,
company: {
// ....
}
}
Problem is, when the save method is called in the back end, the Company member of the Employee object is null. I've tried a few things, like messing with the relationship, adding an Employee list to the Company object, passing the Company object separately, but nothing worked.
What else could I try? Here are some classes:
Record.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import lombok.Data;
#Data
#MappedSuperclass
public abstract class Record {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#NotNull
#Column(name = "deleted")
protected Boolean isDeleted = false;
#NotNull
#Column(name = "enabled")
protected Boolean isEnabled = true;
}
Company.java
package xxx.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import xxx.common.Record;
// ...
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="company")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_company")) } )
public class Company extends Record {
/*
* ...
*/
// Necessary for Hibernate
protected Company() {}
public Company(/* ... */) {
/*
* ...
*/
}
}
Registry.java
package xxx.model.common;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public abstract class Registry extends Record {
#NotBlank
#Column(name = "code", length = 15)
protected String code;
#NotBlank
#Column(name = "name", length = 40)
protected String name;
}
RegistrySingleCompany.java
package xxx.model.common;
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import com.fasterxml.jackson.annotation.JsonBackReference;
import xxx.model.Company;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#MappedSuperclass
public class RegistrySingleCompany extends Registry {
#ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE }, optional= false)
#JoinColumn(name="id_company")
protected Company company;
}
Employee.java
package xxx.model;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import xxx.model.common.RegistrySingleCompany;
import lombok.Data;
import lombok.EqualsAndHashCode;
#Data
#EqualsAndHashCode(callSuper=false)
#Entity
#Table(name="employee")
#AttributeOverrides( { #AttributeOverride(name = "id", column = #Column(name = "id_employee")) } )
public class Employee extends RegistrySingleCompany {
/*
* ...
*/
// Necessary for Hibernate
protected Employee() {}
}
EmployeeRepositoryCustom.java
package xxx.repository.custom;
import org.springframework.data.repository.query.Param;
import xxx.model.Employee;
public interface EmployeeRepositoryCustom {
<S extends Employee> S save(S entity);
}
EmployeeRepositoryCustomImpl.java
package xxx.repository.custom;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;
import xxx.model.Employee;
public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {
#Override
#Transactional
public <S extends Employee> S save(#RequestBody S entity) {
/*
* ...
*/
return entity;
}
}
EmployeeProjection.java
package xxx.model.projection;
import org.springframework.data.rest.core.config.Projection;
import xxx.model.Employee;
#Projection(name = "employeeProjection", types = { Employee.class })
public interface EmployeeProjection {
Boolean getIsDeleted();
Boolean getIsEnabled();
String getCode();
String getName();
/*
* ...
*/
}
EmployeeRepository.java
package xxx.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import xxx.model.Employee;
import xxx.model.projection.EmployeeProjection;
import xxx.repository.custom.EmployeeRepositoryCustom;
#RepositoryRestResource(collectionResourceRel = "employee", path = "employees", excerptProjection = EmployeeProjection.class)
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>, EmployeeRepositoryCustom {}
Thanks in advance.
Edit: added missing classes.
As mentioned before, one of the things I tried was to add an Employee list inside the Company object, which implies using Company's repository instead of the Employee's one to save both objects, but the other object was also arriving null. However, my colleague found out that, by using exported = false inside #RepositoryRestResource(), the value would be received correctly.
That would screw other things up, so we found the following temporary solution:
Create an exported = false repository (EmployeeWrapper) for the sole purpose of delivering the necessary Employee data to construct a new one inside save.
Instead of adding an Employee list inside Company, add an EmployeeWrapper list.
EmployeeWrapper also references Company.
We're still working on a more correct approach.
Update: a more correct approach:
My colleague also found out that, by adding a #Transient Employee list to Company, it's possible to receive the correctly filled out Employee object to save it. I don't know if it works at the repository since, due to other constraints, we moved to use a #RepositoryRestController and are receiving the Company as #RequestBody org.springframework.hateoas.Resource<Company> resource.
We still want to find a better solution, because an Employee list inside Company wasn't planned in our model and, worse yet, we're needing to use list of other things for other methods.
Update: an even better approach:
Experimenting a little more, we created a POJO containing the entities that we needed and received that in the controller, same way as before. Works well.
We're still not satisfied, though. Ideally, we want to receive the Employee to be saved, with the Company to be saved inside it, and save them both at once.
Here my target entity which is User.class is present in a separate jar file.
package com.aa.model;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
#Entity
#Table(name = "ABC")
public class Abc implements Serializable{
---
#OneToOne(targetEntity=com.bb.model.User.class)
#JoinColumn(name = "CREATED_BY")
private User createdBy;
}
---
}
The target class:
package com.bb.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;
#Entity
#Table(name="USER")
public class User implements Serializable {
---
}
I am getting the following error:
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on com.aa.model.Abc.createdBy references an unknown entity: com.bb.model.User
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:109)
at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1598)
In the class Abc, you wrote
#OneToOne(targetEntity=com.bb.User.class)
instead of
#OneToOne(targetEntity=com.bb.model.User.class)
You forgot also the import of com.bb.model package
import com.bb.model.User;
I am trying to implement inheritance but in a way in which is convenient for me to retrieve data. So I have 2 POJOs, one being a parent entity and the other which extends the Parent is the child, Essentially, I'm using the child as a mapper to retrieve values from the Parent table in a key:value pair fashion. So the both keys can be duplicated. Is there any way in which this can be executed. I wanted to create a structure in which one child_Id, can have many different parent_Id's linked to it, in a child_Id:parent_Id, eg. 1:1, 1:2, 2:1, 2:3, 3:1, etc. But due to inheritance I can't duplicate the parent_Id column. Is there a work around. I know it may violate the rules of normalization but is it possible? And if so how?
Computer.java (Parent Entity)
import java.sql.Timestamp;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Entity
#Table(name="Computer", uniqueConstraints={#UniqueConstraint(columnNames = {"tac_Code" , "config_Code"})})
#Embeddable
#Inheritance(strategy=InheritanceType.JOINED)
#NoArgsConstructor
#AllArgsConstructor
#ToString
public abstract class Computer {
#Id
#Column(name = "ID", nullable = false)
#JoinColumn(name="laptop_ID", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Getter
#Setter
protected Long computerId;
......
}
This is the Child class ReplacementComputer.java (Child Entity)
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
* The Class ReplacementComputer
*/
#Entity
#NoArgsConstructor
#AllArgsConstructor
#ToString
#PrimaryKeyJoinColumn(name="computer_id")
public class ReplacementComputer extends Computer implements Serializable {
private static final long serialVersionUID = 1L;
#Getter
#Setter
#OneToMany(cascade = CascadeType.ALL, targetEntity = Product.class)
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JoinColumn(name="REPLACEMENTComputer_ID")
protected Collection<Computer> computers = new ArrayList<Computer>();
// ... getters and setters
}
After it creates 3 tables a Mapping table for the List in ReplacementComputer_computers, Computer being the parent, and ReplacementComputer. So every computer will have several replacementComputers associated with it, the replacementComputer will map back to the Computer table to retrieve the details. This is the flow in which I'm trying to accomplish. But in MySQLWorkbench, if these combinations exist already,
1 , 2
1 , 3
1 , 4
2 , 1
This is the error I get when try to persist (2, 3).
Operation failed: There was an error while applying the SQL script to the database.
Executing:
INSERT INTO testingdb1.replacement_computer_computers (replacement_computer_computer_id, computers_computer_id) VALUES ('2', '3');
ERROR 1062: 1062: Duplicate entry '3' for key 'UK_lbghmganelv3o7oupon6f798c'
SQL Statement:
INSERT INTO testingdb1.replacement_computer_computers (replacement_computer_computer_id, computers_computer_id) VALUES ('2', '3')
Any help is well apreciated, thank you in advance.