None of the similar questions on this site have been able to resolve my problem.
Error: org.hibernate.PersistentObjectException: detached entity passed to persist: healthcheckapi.model.Checks
I am trying to use Hibernate (JPA) to persist two objects to a MYSQL database. "Health" has a oneToMany relationship with "Checks".
Code:
Health Class:
#Entity
#Table(name="health")
public class Health {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String server;
private String description;
private String timestamp;
private String offset;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "health")
private List<Checks> checks;
public Health() {
}
public Health(int id, String server, String description, String timestamp, String offset, List<Checks> checks) {
this.server = server;
this.description = description;
this.timestamp = timestamp;
this.offset = offset;
this.checks = checks;
}
Checks Class:
#Entity
#Table(name="checks")
public class Checks {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int status;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "healthid", referencedColumnName="id")
private Health health;
public Checks() {
}
public Checks(String name, int status) {
this.name = name;
this.status = status;
}
Sample JSON Health Object:
{
"server": "Server18",
"description": "Fine",
"timestamp": "00:02:30",
"offset": "00:01:00",
"checks": [
{ "id": "1",
"name": "cpu",
"status": 90
},
{
"id": "2",
"name": "memory",
"status": 88
},
{
"id": "3",
"name": "apacheService",
"status": 76
}
]
}
Note that the id's for both objects are auto-generated which I think is part of the problem.
Use the CascadeType.MERGE instead of CascadeType.ALL.
Related
I want to create a spring boot rest controller with this specification :
Customers of an electricity and gas supply company can choose to receive their monthly bills either by email or by regular mail, neither or both.
My goal is to create java hibernate entities to manage these customers and their choices of sending bills.
A utility customer is identified by their email and can have multiple choice change events that change the customer choice status.
Each choice made by a customer generates a choice change event.
These my classes:
#Entity
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Email(message="this field must respect the email format !")
private String email;
#OneToMany(mappedBy = "customer")
#MapKey(name="type") //don't need this if you want just a list
private Map<String, Choice> choices;
}
#Entity
#Table(name = "choices")
public class Choice {
#Id
#OneToOne
private Customer customer;
#Id
#Enumerated(EnumType.STRING)
private ChoiceType type;
#Column(name="enabled")
private boolean enabled;
}
#IdClass(EmployeeId.class)
public class ChoiceId implements Serializable {
private Integer customer;
private ChoiceType type;
}
public enum ChoiceType {
MAIL,
EMAIL;
}
#Entity
#Table(name = "customers")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String email;
#OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Choice> choices;
//Getters and Setters
}
#Entity
#Table(name = "choices")
#IdClass(ChoiceId.class)
public class Choice {
#Id
#OneToOne
private Customer customer;
#Id
#Enumerated(EnumType.STRING)
private ChoiceType type;
#Column(name="enabled")
private boolean enabled;
//Getters and Setter
}
public class ChoiceId implements Serializable {
private Integer customer;
private ChoiceType type;
//Getters and Setters
}
public enum ChoiceType {
MAIL,
EMAIL;
}
Services:
CustomerServiceImpl
public CustomerDto addCustomer(CustomerDto customer) {
if(customer.getChoices() !=null) {
for(int i=0; i < customer.getChoices().size(); i++) {
ChoiceDto choice = customer.getChoices().get(i);
choice.setCustomer(customer);
customer.getChoices().set(i,choice);
}
} else {
customer.setChoices(Collections.<ChoiceDto>emptyList());
}
ModelMapper modelMapper = new ModelMapper();
Customer customerEntity = modelMapper.map(customer, Customer.class);
Customer newCustomer = customerRepository.save(customerEntity);
CustomerDto customerDto = modelMapper.map(newCustomer, CustomerDto.class);
return customerDto;
}
ChoiceServiceImpl
public ChoiceDto addChoice(ChoiceDto choiceDto, String email) {
Customer customerWithChoice = customerRepository.findByEmail(email);
ModelMapper modelMapper = new ModelMapper();
CustomerDto customerDto = modelMapper.map(customerWithChoice, CustomerDto.class);
choiceDto.setCustomer(customerDto);
Choice choiceEntity = modelMapper.map(choiceDto, Choice.class);
Choice newChoice = choiceRepository.save(choiceEntity);
ChoiceDto newChoiceDto = modelMapper.map(newChoice, ChoiceDto.class);
return newChoiceDto;
}
I want to get these results :
Post(create customer):
{
"id": "1289",
"email": "customer#eamil.com",
"choices": []
}
If two events are created in this order:
Post(create choices):create of two choices in this order
{
"user": {
"id": "1289"
},
"choices": [
{
"id": "MAIL",
"enabled": true
}
]
}
{
"user": {
"id": "1289"
},
"choices": [
{
"id": "MAIL",
"enabled": false
},
{
"id": "EMAIL",
"enabled": true
}
]
}
GET particular customer :
{
"id": "1289",
"email": "customer#eamil.com",
"choices": [
{
"id": "MAIL",
"enabled": false
},
{
"id": "EMAIL",
"enabled": true
}
]
}
But it doesn't give me the same result ? How can i resolve this problem in my entities or service implementation
Good night everyone,
I want to model a database that has the following entities and their perspective relationships:
But everytime I run the Java project to create the model at database, what I create is something like this:
There is another way to map this relationship? I'm mapping like that:
Article entity:
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private Boolean featured;
#Column(nullable = false)
private String title;
#Column(nullable = false)
private String url;
#Column(name = "image_url", nullable = false)
private String imageUrl;
#Column(name = "news_site", nullable = false)
private String newsSite;
#Column(nullable = false)
private String summary;
#Column(name = "published_at", nullable = false)
private String publishedAt;
#OneToMany
#JoinColumn(name = "launches_id")
private List<Launches> launches;
#OneToMany
#JoinColumn(name = "events_id")
private List<Events> events;
}
Launches entity
#Entity
public class Launches {
#Id
private String id;
private String provider;
}
Events entity:
#Entity
public class Events {
#Id
private Long id;
private String provider;
}
And I want to map this JSON, with this same launcher and events appearing in other articles:
{
"id": 4278,
"title": "GAO warns of more JWST delays",
"url": "https://spacenews.com/gao-warns-of-more-jwst-delays/",
"imageUrl": "https://spacenews.com/wp-content/uploads/2019/08/jwst-assembled.jpg",
"newsSite": "SpaceNews",
"summary": "",
"publishedAt": "2020-01-28T23:25:02.000Z",
"updatedAt": "2021-05-18T13:46:00.284Z",
"featured": false,
"launches": [
{
"id": "d0fa4bb2-80ea-4808-af08-7785dde53bf6",
"provider": "Launch Library 2"
}
],
"events": []
},
{
"id": 4304,
"title": "Government watchdog warns of another JWST launch delay",
"url": "https://spaceflightnow.com/2020/01/30/government-watchdog-warns-of-another-jwst-launch-delay/",
"imageUrl": "https://mk0spaceflightnoa02a.kinstacdn.com/wp-content/uploads/2020/01/48936479373_2d8a120c8e_k.jpg",
"newsSite": "Spaceflight Now",
"summary": "",
"publishedAt": "2020-01-30T04:08:00.000Z",
"updatedAt": "2021-05-18T13:46:01.640Z",
"featured": false,
"launches": [
{
"id": "d0fa4bb2-80ea-4808-af08-7785dde53bf6",
"provider": "Launch Library 2"
}
],
"events": []
}
According to your diagram, it should be:
#ManyToOne
#JoinColumn(name = "launches_id")
private Launches launches;
#ManyToOne
#JoinColumn(name = "events_id")
private Events events;
...and not #OneToMany ;) (Can there be an "Article" (with id=x) having launchers_id=y AND launchers_id=z? No, vice versa!:)
...for the #OneToMany, you should find the join columns "on the other side" (of relationship(s)).
According to your JSON, it is OneToMany. But then, we have to draw/expect:
#Entity
class Article {
//... id, columns, blah
#OneToMany
#JoinColumn(name = "article_id") // Launches "owns the relationship"/column
private List<Launches> launches;
#OneToMany
#JoinColumn(name = "article_id") // Events...!
private List<Events> events;
}
Generally, (when you expose your db model via json,) ensure:
no "circles" (in bi-directional associations). (#JsonManagedReference, #JsonBackReference, #JsonIgnoreProperties, ... )
not to expose data, that you don't want to expose. (#JsonIgnoreProperties, ...)
Regarding Hibernate-ManyToOne, please refer to https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/
Regarding spring-data-jpa, best to:
gs-data-jpa
gs-data-rest
spring-boot-ref, data-jpa
reference-doc, data-jpa
reference-doc, data-rest
I need to put and get data from MySql with spring boot (Hibernate, Jackson)
Sample JSON:
[
{
"name": "Product1",
"colors": [
{
"color": [
"#dddd33",
"#676767"
]
},
{
"color": [
"#FFdDFF"
]
}
]
}
]
Same JSON I want to receive but added "id". What should I do to achieve this?
Object:
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonProperty("name")
private String name;
#JsonProperty("colors")
#OneToMany(mappedBy = "product_id")
private Set<Color> colors;
}
#Entity
public class Color {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Long product_id;
#JsonProperty("color")
#CollectionTable(name = "color", joinColumns = #JoinColumn(name = "color_id"))
#Column(name = "color")
#ElementCollection
#OrderBy
private List<String> color;
}
This not work
I get error
java.sql.SQLException: Field 'id' doesn't have a default value
I am developing simple API for practice project Online Shopping system. Since I am very new in working with APIs, I am having a trouble with my Entities and relationships. First, I give all my schema and classes before introduce the problem.
Here is a link for my database schema.
These are #Entity classes:
----
#Entity
#Table(name = "Customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "country")
private String country;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
// constructor, getters, setters ....
#Entity
#Table(name = "Order")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "date")
private Date date;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cust_id", nullable = false)
#JsonIgnore
private Customer customer;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> details = new ArrayList<>();
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Invoice> invoices = new ArrayList<>();
//constructor, setters, getters ....
#Entity
#Table(name = "Product")
public class Product {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "price")
private Double price;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> orderDetails = new ArrayList<>();
//cons, setters, getters ...
#Entity
#Table(name = "Detail")
public class Detail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ord_id", nullable = false)
#JsonIgnore
private Order order;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pr_id", nullable = false)
#JsonIgnore
private Product product;
#Column(name = "quantity")
private int quantity;
//similar classes for Invoice and Payment (no problem with them)
Here is my Sample Repository class:
#Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
Also here is my controller class:
#RestController
public class OnlineShoppingApiController {
#Autowired
ProductRepository productRepository;
#Autowired
OrderRepository orderRepository;
#Autowired
CustomerRepository customerRepository;
#Autowired
DetailRepository detailRepository;
#Autowired
InvoiceRepository invoiceRepository;
#Autowired
PaymentRepository paymentRepository;
#GetMapping("/products")
public List<Product> getProductsList(){
return productRepository.findAll();
}
#GetMapping("/customers")
public List<Customer> getCustomersList(){
return customerRepository.findAll();
}
#GetMapping("/orders")
public List<Order> getOrdersList(){
return orderRepository.findAll();
}
#GetMapping("/invoices")
public List<Invoice> getInvoicesList(){
return invoiceRepository.findAll();
}
#GetMapping("/payments")
public List<Payment> getPaymentsList(){
return paymentRepository.findAll();
}
#GetMapping("/details")
public List<Detail> getDetailsList(){
return detailRepository.findAll();
}
I am doing the same approach for all APIs and relationships.
When I call for /products in postman, I am getting result JSON like this:
[{
"id": 3,
"name": "pname_816",
"description": "pdesc_871_871_871_87",
"price": 1.41,
"orderDetails": [
{
"id": 9,
"quantity": 831
},
{
"id": 51,
"quantity": 701
},
{
"id": 87,
"quantity": 310
}
]
},
{
"id": 4,
"name": "pname_395",
"description": "pdesc_495_495_495_49",
"price": 26.65,
"orderDetails": [
{
"id": 85,
"quantity": 853
}
]
}]
Same fine results for /details, /invoices, and /payments.
The problem is if I send GET request for /customers, the result:
{
"timestamp": "2018-04-05T11:53:39.558+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not write JSON: could not extract ResultSet; nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.project.pojo.Customer[\"orders\"])",
"path": "/customers"
}
And if i send request for /orders, the result is:
{
"timestamp": "2018-04-05T11:54:37.316+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet",
"path": "/orders"
}
The same approach is not working for all. I cannot understand where the problem is. Please help me to find it.
Thanks for the answer
I have finally found the answer by myself. Here the problem is not with Annotation or key referencing but with the naming the Entities.
Since order is reserved keyword for MySql, naming the entity and variables like this causes unexpected problems.
So I have just changed the Entity name to Orders in schema and code and working fine.
Hope this post will help for others too
I have an entity
#Entity
public class Post {
#Id
private Long id;
#NotNull
private Date createdAt;
#NotNull
private String text;
#NotNull
private Date updatedAt;
#OneToMany
private List<Comment> comments;
}
and another entity
#Entity
public class Comment {
#Id
private Long id;
#NotNull
private Date createdAt;
#NotNull
private String text;
#NotNull
private Date updatedAt;
}
and I have a simple controller that returns post json given id
#RestController
#RequestMapping("/posts")
public class ProductDimensionsController {
#RequestMapping(method = RequestMethod.GET)
public Post getPost(#RequestParam(value = "id") String id) throws ApiException {
...
...
...
}
}
I am getting in response:
{
"id": 401,
"createdAt": 1482364510614,
"updatedAt": 1482364510614,
"text": "abc",
}
I want follwing:
{
"id": 401,
"createdAt": 1482364510614,
"updatedAt": 1482364510614,
"text": "abc",
"comments": [{
"id": 101,
"createdAt": 1482364510614,
"updatedAt": 1482364510614,
"text": "xyz",
}]
}
How can I include associated OneToMany entities in the json response?
In order to get the result you want, you will have to mark the #ManyToOne(fetch = FetchType.LAZY) on the Comment entity. This will result in fetching the results in FetchType.LAZY mode.
Another approach could be:
#Entity
public class Post {
#Id
private Long id;
#NotNull
private Date createdAt;
#NotNull
private String text;
#NotNull
private Date updatedAt;
#OneToMany
#JsonIgnore
private List<Comment> comments;
#JsonIgnore
public List<Comment> getComments() {
return comments;
}
#JsonProperty
public void setComments(List<Comment> comments) {
this.comments = comments;
}
}