when i updating the records via postman record not updating it will create a new record i don't know why.i attached screenshot below along with code what i tried so far.i have attched the controller,service,
entity,repository.
i am tring this since yesterday problem not solved please some one will help me to solve
enter image description here
EmployeeController
#PutMapping("/edit/{id}")
private Employee update(#RequestBody Employee employees,#PathVariable(name = "id") long id)
{
Employee emp = services.get(id);
services.saveOrUpdate(emp);
return employees;
}
Services
//updating a record
//updating a record
public void update(Employee employees, int id)
{
repo.save(employees);
}
Repository
#Repository
public interface EmployeeRepository extends CrudRepository<Employee,Long> {
}
Entity
#Entity
#Table(name="Records")
public class Employee {
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name="fname")
private String fname;
#Column(name="lname")
private String lname;
#Column(name="city")
private String city;
#Column(name="phone")
private String phone;
#Column(name="salary")
private String salary;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getSalary() {
return salary;
}
public void setSalary(String salary) {
this.salary = salary;
}
}
This an example of UPDATE and it worked for me.
//HTTP PUT
#PutMapping("/owners/{id}")
public void updateOwner(#RequestBody Owner owner, #PathVariable int id) {
owner.setId(id);
ownerRepos.save(owner);
}
I used the CrudRepository too.
Also I notice that you call services.saveOrUpdate(emp) but at the same time you showed us "public void update(Employee employees, int id)" below. If'd better if you could show the definition of the method saveOrUpdate()
SaveOrUpdate uses the ID of the object to determine if the object is the same or new. When updating, you're not considering the ID of the employee. You should first fetch the Object from DB and update the same object. The updates should take place on a persistent object
Related
I faced with problem of null value in PK.
Here's an entity:
#Entity
#Table(name="space")
public class Space implements Serializable {
#Id
#GeneratedValue
#Column(nullable = false, unique = true)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private UserAccount user;
private String name;
private String description;
private Date createdTime;
private Date modifiedTime;
#OneToMany(mappedBy="space")
private Set<SpaceAccess> spaceAccesses = new HashSet<>();
public Set<SpaceAccess> getSpaceAccesses() {
return spaceAccesses;
}
public void setSpaceAccesses(Set<SpaceAccess> spaceAccesses) {
this.spaceAccesses = spaceAccesses;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Space() {}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public UserAccount getUser() {
return user;
}
public void setUser(UserAccount user) {
this.user = user;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
}
I wrote strategy to generate PK properly but I always get Null in id field when I create new instance of the Space:
Space space = new Space();
Here's content of the object:
What i should do to generate id of instance properly using hibernate/spring mechanisms?
application.properties:
spring.datasource.url="some_url"
spring.datasource.username=name
spring.datasource.password=password
spring.jpa.generate-ddl=true
P.S. I use spring-boot-starter-data-jpa with version: 2.3.4.RELEASE.
Use:
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
My AuditListener
public class EmployeeAuditListeners {
#PrePersist
public void prePersist(Employee employee){
perform(employee,Action.INSERTED);
}
#PreUpdate
public void preUpdate(Employee employee){
perform(employee,Action.UPDATED);
}
#PreRemove
public void preRemove(Employee employee){
perform(employee,Action.DELETED);
}
#Transactional
public void perform(Employee emp, Action action){
EntityManager em = BeanUtil.getBean(EntityManager.class);
CommonLogs commonLogs = new CommonLogs();
commonLogs.setQuery("new query");
em.persist(commonLogs);
}
}
and My Auditable.class
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {
#CreatedBy
protected U createdBy;
#CreatedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date createdDate;
#LastModifiedBy
protected U lastModifiedBy;
#LastModifiedDate
#Temporal(TemporalType.TIMESTAMP)
protected Date lastModifiedDate;
}
My CommonLogs.class
#Entity
#EntityListeners(AuditingEntityListener.class)
public class CommonLogs extends Auditable<String> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String query;
public CommonLogs() {
}
public CommonLogs(String query) {
this.query = query;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
My Employee.java class
#Entity
#EntityListeners(EmployeeAuditListeners.class)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
and I have a simple Rest Controller
#RestController
#RequestMapping("/api")
public class EmployeeController {
#Autowired
private EmployeeRepository employeeRepository;
#PostMapping("/employees")
public Employee createEmployee(#RequestBody Employee employee){
return employeeRepository.save(employee);
}
}
I want to log it on my table (common_logs) every time i perform some crud operations on my Employee Entity.
the above given example is working to some extent as it successfully stores employee and invokes EmployeeAuditListeners.
but now while saving CommongLog entity i expect it's parent class Auditable to automatically insert createdBy, createdDate etc. for now only query and id is inserted on common_logs table and remaining columns are null.
You can review the documentation for Auditing in here.
To enable the automatic Auditing, you must add the annotation #EnableJpaAuditing in your Application class:
#SpringBootApplication
#EnableJpaAuditing
class Application {
static void main(String[] args) {
SpringApplication.run(Application.class, args)
}
}
If you want the fields #CreatedBy and #LastModifiedBy too, you will also need to implement the AuditorAware<T> interface. For example:
class SpringSecurityAuditorAware implements AuditorAware<User> {
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}
i am try to create a one to many bidirectional mapping using spring boot and spring data jpa please look the below entity
Employer Entity
#Entity
public class Employer
{
private Long id;
private String employerName;
private List<Employee> employees;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getEmployerName()
{
return employerName;
}
public void setEmployerName(String employerName)
{
this.employerName = employerName;
}
#OneToMany(cascade=CascadeType.ALL, mappedBy="employer")
public List<Employee> getEmployees()
{
return employees;
}
public void setEmployees(List<Employee> employees)
{
this.employees = employees;
}
}
Employee Entity
#Entity
public class Employee
{
private Long id;
private String employeeName;
private Employer employer;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getEmployeeName()
{
return employeeName;
}
public void setEmployeeName(String employeeName)
{
this.employeeName = employeeName;
}
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
public Employer getEmployer()
{
return employer;
}
public void setEmployer(Employer employer)
{
this.employer = employer;
}
}
Employer Repo
public interface EmployerServices extends JpaRepository<Employer, Long> {
}
Employee Repo
public interface EmployeeServices extends JpaRepository<Employee, Long> {
}
REST Controller is
#RestController
public class Controller {
#Autowired EmployeeServices employeeServices;
#Autowired EmployerServices employerServices;
#GetMapping("/getempr")
public Object getempr(){
return employerServices.findOne(1L);
}
}
now the problem begin start see my out put
its look like a infighting loop and my server throwing error getOutputStream() has already been called for this response.
I used #JsonBackReference & #JsonManagedReference
annotation but the problem is its working like one to many
{
"id":1,
"employerName":"employer",
"employees":[
{"id":1,"employeeName":"emp1"},
{"id":2,"employeeName":"emp2"}
]
}
if I am trying to get in the concern of many to one like all employee with employer. the output is
[
{
"id":1,
"employeeName":"emp1"
},
{
"id":2,
"employeeName":"emp2"}
]
its not showing me the employer details.
please suggets me guys what i am doing wrong. thanks in advance!!
Instead of using #JsonBackReferenceand #JsonManagedReference try to use annotation #JsonIgnoreProperties:
#JsonIgnoreProperties("employer")
private List<Employee> employees;
#JsonIgnoreProperties("employees")
private Employer employer;
It prevents Jackson from rendering a specified properties of associated objects.
with the JSON its a problem with bi-directional mapping. Use the below properties.
#JsonIgnoreProperties("employer")
#JsonIgnoreProperties("employees")
please keep fetching type as eager.
hope this will work.
You can solve your issue with two modification with annotations.
Employer.class
#Entity
public class Employer {
private Long id;
private String employerName;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "employer",
orphanRemoval = true)
private List<Employee> employees;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmployerName() {
return employerName;
}
public void setEmployerName(String employerName) {
this.employerName = employerName;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
Employee.class
#Entity
public class Employee {
private Long id;
private String employeeName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employer_id")
private Employer employer;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employer getEmployer() {
return employer;
}
public void setEmployer(Employer employer) {
this.employer = employer;
}
}
For more information please visit this link.
Change your getEmployer Method like this:
#ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public Employer getEmployer()
{
return employer;
}
use
#JsonProperty(access = Access.WRITE_ONLY)
private List<Employee> employees;
So that it will ignore employees while printing to JSON in the response (and thus prevents the looping), but will still consider the JSON data (employee list) you pass in the request body so that it is available for persistence.
the user entity
import javax.persistence.*;
#Entity
public class User {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private Integer age;
#Embedded
private Address address;
public User(){}
public User(String name, Integer age,Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
and the address entity
#JsonInclude(JsonInclude.Include.NON_NULL)
#Embeddable
public class Address {
private String city;
public Address() {
}
public Address( String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
the controller code
#ResponseStatus(HttpStatus.CREATED)
#RequestMapping(value = "users", method = RequestMethod.POST)
public void users(#RequestBody List<User> users) {
this.userRepository.save(users);
}
when i post json data with psot man, the data is
[
{
"name":"yaohao",
"age":11,
"address":{
"city":"nantong"
}
},
{
"name":"yh",
"age":11,
"address":{
"city":"nantong"
}
}
]
the address always null
when the user entity has no #Embedded address entity,the code works fine,so how can i post json data to controller when i use #Embedded annotations
It has nothing to do with the use of #Embedded. When doing the marshaling Jackson uses Java Bean properties to set the values and as your User class is lacking a getAddress and setAddress Jackson simply ignores it because it doesn't exists.
To fix add the getter and setter for Address.
Or instead of using property access switch your mapper to use field access. See how to specify jackson to only use fields - preferably globally for more information on that.
I've got problem with my entities. I've trade to make many-to-one connection between this two entities. I'm doing it like that:
User user = new User();
user.setName("a");
user.setLastName("b");
Set<Adress> a = new HashSet<Adress>();
Adress a1 = new Adress();
Adress a2 = new Adress();
a1.setCity("a1");
a2.setCity("a2");
a.add(a1);
a.add(a2);
user.setAdress(a);
userProxy.save(user);
My entites:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#NotNull
private String name;
#NotNull
private String lastName;
#OneToMany(mappedBy="user", cascade=CascadeType.ALL)
private Set<Adress> adress = new HashSet<Adress>();
public User(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public User() {
}
public Set<Adress> getAdress() {
return adress;
}
public void setAdress(Set<Adress> adress) {
this.adress = adress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Long getId() {
return id;
}
}
Second Entity
#Entity
public class Adress {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Long id;
private String city;
#ManyToOne
#JoinColumn(name="user_id")
private User user;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Long getId() {
return id;
}
}
Data in table User saves fine, but in table adress field user_id is "NULL" can anyone explain to me why is that? I've tried a lots of combinations with #ManyToOne but nothing worked for me.
For more details UserProxy:
#Service
public class UserProxyDao {
private UserDao userDao;
#Autowired
public UserProxyDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(User user) {
userDao.save(user);
}
}
however if i put #NotNull on field user in Adress entity validation fails... I really dont know why is that
Caused by: javax.validation.ConstraintViolationException: validation failed for classes [pl.rd.j2ee.api.domain.Adress] during persist time for groups [javax.validation.groups.Default, ]
You should be able to do this in one action as long as you do this first.
a1.setUser(user);
a2.setUser(user);
You could always add User to your Address constructor and do it there.
public Address (User user) {
this.user = user;
}