Does not save an enum value in the database, I think that's it, or I do not understand, I try to save since the console shows me a data, but when I ask from the database I get another value
#Entity
#Table(name = "User")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "name")
private String name;
#Column(name = "password")
private String password;
#Column(unique = true, name = "email")
private String email;
#Column(name="rol")
Rol rol;
#Column(name = "life")
Life life;
public User() {
}
}
i have this in the .info, show this message "OWNER"
Set<User> users =new HashSet<>();
log.info("CONSOLE"+ user.getRol());
users.add(user);
meet.setUsers(users);
return meetRepository.save(meet);
but in swagger i get other value
ROL: PARTICIPANT
[
{
"id": 1,
"name": "string2",
"state": "pause",
"bet": {
"profit": 0,
"inversion": 0
},
"users": [
{
"id": 1,
"name": "string",
"password": "string",
"email": "ema",
"rol": "PARTICIPANT",
"life": "suspend"
}
]
}
]
If your fields rol and life are Enums you have to declare them as Enums with #Enumerated. There are two options. Default will store the ordinal number. Or you can choose to use the string name to store in the DB. That's the better option in terms of maintainability:
#Enumerated(EnumType.STRING)
#Column(name="rol")
Rol rol;
#Enumerated(EnumType.STRING)
#Column(name = "life")
Life life;
Two remarks:
When the database field has the same name as the attribute you can omit #Column. And if the table has the same name as the entity this is also true for the #Table annotatoin.
Read more about Enums and JPA and if you really should use it in one of my articles: https://72.services/de/should-you-use-enums-with-jpa/
When you save a Enum to the database as stated above you have the option of saving it as String or as Numerical Ordinal. The numerical option is very painfull because every time you need to update your enum values or change the order of the values you will mess with your database options for the field. Also another thing that is very painfull even when you store the strings on the database is that when you are using some ORM such as Hibernate and you have NULL values. So keep your enums as strings and avoid NULL value.
Related
I have following entities:
#Entity
#Table(name = "profile")
public class Profile {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL)
private ProfileContacts profileContacts;
...
}
and
#Entity
#Table(name = "profile_contacts")
public class ProfileContacts {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "description")
private String description;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
}
I am trying to update it by sending this JSON with update to REST controller:
{
"id": 1,
"description": "an update",
"profileContacts": {
"firstName": "John",
"lastName": "Doe"
}
}
so in the end it calls
profileRepository.save(profile);
where profileRepository is instance of ProfileRepository class:
public interface ProfileRepository extends JpaRepository<Profile, Long> {
}
which is spring-data-jpa interface.
But each time after such update it updates profile table but adds new row to profile_contacts table (table which corresponds to ProfileContactsentity) instead of updating existing ones.
How can I achieve updating?
As per your JSON structure. Yes it will create new profileContacts entry for every time.
The problem every time while saving profile entity you are passing "id": 1 that means Hibernate can identify the entity by this id value (primary key) but for profileContacts mapping you are not sending the id that's why Hibernate considering it has a new entity every time.
To update your profileContacts entity make sure to pass the id of it.
Example:
{
"id": 1,
"description": "an update",
"profileContacts": {
"id" : yourEntityId
"firstName": "John",
"lastName": "Doe"
}
}
Well, that's the expected behavior.
You're not telling hibernate to update the profileContacts.
For the framework to be able to update it, you need to send the profileContact's primary key - which in your case is the ProfileContacts#id.
Something like this:
{
"id": 1,
"description": "an update",
"profileContacts": {
"id": 1
"firstName": "John",
"lastName": "Doe"
}
}
Need to specify the join column in the parent Entity.
#Entity
#Table(name = "profile")
public class Profile {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL)
**#JoinColumn(name = "id")** //
private ProfileContacts profileContacts;
...
}
Now when you try to save Profile entity it will save the child entity also.
And also needs to include Id in jason request for child entity also
{
"id": 1,
"description": "an update",
"profileContacts": {
"id": 1,
"firstName": "John",
"lastName": "Doe"
}
}
Ok, I see the problem. As #Matheus Cirillo pointed out, you need to tell the hibernate to update the row.
Now, how do you tell the hibernate to update a row - By providing the primary key of the existing row.
But, creating an object with the primary key set is not enough. You need that entity class to be attached to the entity manager and the persistence context.
You can have something like,
//This attaches the entity to the entity manager
ProfileContacts existingProfileContacts = profileContactRepository.getOne(2);
Profile profile = new Profile();
....
....
profile.setProfileContacts(existingProfileContacts);
profileRepository.save(profile);
I hope this helps.
I am trying to map an array of Objects to a field. All the fields in that object are being mapped to columns with different name but similar structure. The response structure should be:
"customers": [
{
"firstName": "string",
"lastName": "string",
"products": [
{
"description":"string",
"amount": "string"
},
{
"description":"string",
"amount": "string"
}
]
}
]
Inside the products field, I have a list of product(description and amount). In DB, columns are stored like
product_des1,product_amt1,product_des2,product_amt2.....product_des30,product_amt30
. I need to map these two fields to the product(object). How should I approach to solve the problem using JPA annotations if possible?
For the reference:
Customers.class
#Entity
public class Customers implements Serializable {
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#ElementCollection
List<Products> products;
}
Product.class
#Embeddable
public class Product implements Serializable {
#Column(?)
private String description;
#Column(?)
private String amount;
}
Inside the products field, I have a list of product(description and amount). In DB, columns are stored like
product_des1,product_amt1,product_des2,product_amt2.....product_des30,product_amt30
So your Products JPA entity should simply look like this:
#Embeddable
public class Products implements Serializable {
#Column(name = "product_des1")
private String description1;
#Column(name = "product_amt1")
private String amount1;
#Column(name = "product_des2")
private String description2;
#Column(name = "product_amt2")
private String amount2;
// ... repeat
}
if you don't want to do additional mapping between the DB and JPA entities (which I don't recommend - I try to keep JPA entities as exact representation of a DB row and map, if necessary, in Java and not between different technologies).
Is there any alternative ways to enforce foreign key constraints with JPA, Hibernate, etc. to minimize to data stored against a POJO?
I have a spring boot project with User and Form Model, Dao, and Controller classes that is connected to a MySQL database. A User can have many Forms but a Form can only have one User. So the relationship is one to many. To enforce the foreign key constraint I use the #OneToMany annotation with a List. With this design, when I use an HTTP GET method in postman, a single user returns the user AND all his/her associated forms, which I don't like. Is there another way to enforce the a foreign key constraint such that I don't have to store all the information against the User class, but ensure referential integrity within the database?
Below is my User Class. At the bottom is where I create a List of type Form and annotate it with the #OneToMany annotation and then tell it which attribute in the form class to join it with using the #JoinColumn
package org.hoa.HOA_Website.WebsiteDatabaseAPI.Entities;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.List;
#Entity
#Table
public class User {
#Id
#GeneratedValue
#Column(name = "user_id", insertable = false, updatable = false)
private Long userID;
#NotBlank
#Column(length = 30, nullable = false)
private String firstName;
#NotBlank
#Column(length = 30, nullable = false)
private String lastName;
#NotBlank
#Column(length = 30)
private String middleName;
#NotBlank
#Column(length = 14)
private String phoneNumber;
#NotBlank
#Column(length = 50, unique = true, nullable = false)
private String email;
#Column(nullable = false)
private Boolean admin;
private int age;
#NotBlank
#Column(length = 100, nullable = false)
private String passwordHash;
#OneToMany(targetEntity = Form.class, cascade = CascadeType.ALL)
#JoinColumn(name = "submitter_id")
private List<Form> formsMade;
/*
Getters and Setters Below
*/
Now below here is the Form Class. Above submitter I have the column named such that it will match the #JoinColumn annotation. This ensures that all submitter ids sent via a POST method having a matching user id.
package org.hoa.HOA_Website.WebsiteDatabaseAPI.Entities;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table
public class Form {
#Id
#GeneratedValue
private Long formID;
#Column(nullable = false)
private Date dateSubmitted;
#Column(name = "submitter_id", nullable = false)
private Long submitter;
#Column(nullable = false)
private Boolean approvalStatus;
#Column(length = 30, nullable = false)
private String formType;
/*
Getters and Setters Below
*/
BUT, when i perform a GET method to find all the Users. I get all the Users AND their associated Forms.
[
{
"userID": 1,
"firstName": "Jane",
"lastName": "Doe",
"middleName": "Halyard",
"phoneNumber": "1234567890",
"email": "janedoe#gmail.com",
"admin": false,
"age": 20,
"passwordHash": "klsjfougalsdg2e98y54e982ajsdng924uierg",
"formsMade": [
{
"formID": 5,
"dateSubmitted": "2019-06-11T12:25:43.000+0000",
"submitter": 1,
"approvalStatus": false,
"formType": "ConstructionForm"
},
{
"formID": 6,
"dateSubmitted": "2019-06-11T12:25:43.000+0000",
"submitter": 1,
"approvalStatus": false,
"formType": "HardshipForm"
}
]
},
{
"userID": 2,
"firstName": "John",
"lastName": "Doe",
"middleName": "Michael",
"phoneNumber": "0987654321",
"email": "johndoe#gmail.com",
"admin": true,
"age": 32,
"passwordHash": "klsjfougalsdg2e98y5423bt49sdgajsdng924uierg",
"formsMade": [
{
"formID": 3,
"dateSubmitted": "2019-06-11T12:25:43.000+0000",
"submitter": 2,
"approvalStatus": false,
"formType": "HardshipForm"
}
]
}
]
So finally, is there anyway to ensure referential integrity but without storing so much on the User? Hopefully more like relational data structures and just store the foreign key on the Form?
I think what you are after is a DTO.
Is there any alternative ways to enforce foreign key constraints with JPA, Hibernate, etc. to minimize to data stored against a POJO?
Discussing about a POJO is a bit inaccurate. Your Entities define ORM and those should be defined as they are. You should think about what is the data you return. Your entiteis do not actually store the data but you populate them with all the data and return all that data if you query and return them as they are, so using them also as DTOs.
It seems that you return Collection<User> (so entities) as a response.
Instead you should return a collection of DTOs - say - Collection<SimpleUserDTO> where DTO could be like:
public class SimpleUserDTO {
public Long userID;
public String firstName;
public String lastName;
public String middleName;
public String phoneNumber;
public String email;
public Boolean admin;
public int age;
public String passwordHash;
// NOTE: no formsMade here!
}
So your Controller method should call Service method that returns this collection of DTOs that it obtains from some Repository method either already mapped as DTOs or as entities that Service method then maps one by one to be a DTO.
In your Service method you could map entity values to DTO - field by field or perhaps with a library like ModelMapper - but best way in my opinion would be that you implemented a Repository method ( with a Projection or a Tuple query) that populates this DTO straight from the query and lets the Service method call that.
And after all this very ugly but easy way to achive this same would just loop the users in your Controller and set the formsMade to null but it is finally a very inefficient solutions and will not be a flexible way to hanled all this conversion stuff later with different results etc...
There is a lot of stuff to explain more in details but I hope that with this information you might be able to find more information from SO or elsewhere in relevant documentation.
And: of course you need to map back from DTO to entity then when passing data to Controller.
I have a JSON like this:
{
"pcSignatureHash": "String",
"pcSignature": "String",
"infectedBy": "String",
"agent": {
"userCode": 0
},
"pc": {
"name": "String",
"userName": "String",
"osType": "String",
"domainName": "String",
"cpuId": "String",
"osVersion": "String",
"macId": "String",
"vm": true,
"friendlyName": "String",
"statuses": [
{
"firewall": true,
"firewallTestDate": "String"
}
]
}
}
It's not storing the statuses in the database.
The infections has 1 to 1 relationship with pcs and pcs has 1 to Many relationship with the statuses.
The models are properly set like 1 have Infections in PCs and have Set<Statuses> in the PCs and Statuses has PCs in its model.
Is there any other way to store the data?
If I store the statuses separately that doesn't make a sense it stores the PCs twice because we need to pass the PCs object as a foreign key.
You missunderstood the Relational Mapping. In a OneToMany Relationship you have one side with #OneToMany and one with #ManyToOne.
Your entities should be like below .
please modify accordingly.
Cart entity
#Entity
#Table(name="CART")
public class Cart {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="cart_id")
private long id;
#Column(name="total")
private double total;
#Column(name="name")
private String name;
#OneToMany(mappedBy="cart")
private Set<Items> items;
// Getter Setter methods for properties
}
Item Entity
#Entity
#Table(name="ITEMS")
public class Items {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private long id;
#Column(name="item_id")
private String itemId;
#Column(name="item_total")
private double itemTotal;
#Column(name="quantity")
private int quantity;
#ManyToOne
#JoinColumn(name="cart_id", nullable=false)
private Cart cart;
// Getter Setter methods for properties
}
i'm currently building a rest-api with Java-EE/Jax-RS/JPA.
I already have a working database + database model and used the eclipse option for creating jpa-entities from existing tables.
I've created some basic services and i'm curious now whether the use of jpa-associations makes sense for building a rest-api or not because it sometimes leads to a big chunk of data getting exposed. I'm also unsure about where to separate the data that is being exposed.
E.g:
table "FOLDER" has an id, name
table "FOLDER_ITEM" has an id, folder_id (fk), item_id (fk)
table "ITEM" has an id, name, itemprop_id(fk)
table "ITEM_PROP" has an id, valueA, valueB, valueC
Calling /folders/1 currently outputs:
{
"id": 1,
"name": "Folder1",
"items": [
{
"id": 1,
"name": "pencil",
"item_prop": {
"id": "1",
"valueA": "example",
"valueB": "example",
"valueC": "example"
}
},...]
}
which adds up to a lot of data if there are a lot of items connected to a folder.
So i thought it maybe simpler and cleaner to separate the data by creating a service /items/{id} which would give me only one item at a time.
But in this case i would also have to create a service for getting the items of a folder. E.g /items/?withFolderId=1
or even /folders/1/items. I see the following options:
1) use jpa-associations but mark the list of items (inside the folder-class) as json-ignored for /folders/1 and force the output of the items when calling /folders/1/items.
2) write queries on my own
in case of the latter i'm asking my self "why would i even use jpa at all?"
While beeing confused by this i might also have to say that all my tables have a foreign key to a user-id.
So i usually only want to get the folders of a specific user (the user who is currently logged in) by creating a service /users/1/folders and at this point where would i separate the data ?
I could serve my entire client from the /users/ endpoint which would lead to the same problem as above. And now we can definitely talk about a big chunk of data getting exposed, depending on how much folders a user has and how much items the folders contain.
{
"id":1
"name":"testuser"
"password":"PW"
"folders":
[{
"id": 1,
"name": "Folder1",
"items": [
{
"id": 1,
"name": "pencil",
"item_prop": {
"id": "1",
"valueA": "example",
"valueB": "example",
"valueC": "example"
}
},....]
},....]
}
I feel like i'm distracting myself a lot with this problem. Are there any suggestions or common ways to solve this problem ?
if you are using jackson library then you can mention #JsonIgnore to avoid json response. Following Example code.
#Entity
#Table(name="address")
#EqualsAndHashCode(exclude={"id","companies","clientDetails"})
#Getter
#Setter
#NoArgsConstructor
#ToString(exclude = {"companies","clientDetails"})
#JsonIgnoreProperties(ignoreUnknown = true)
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private Integer id;
#Column(name="address_line1")
private String addressLine1;
#Column(name="address_line2")
private String addressLine2;
#Column
private String city;
#Column
private String country;
#Column(name="phone_no")
private String phoneNo;
#Column(name="postal_code")
private String postalCode;
#Column
private String state;
//bi-directional many-to-one association to ClientDetail
#OneToMany(mappedBy="addressBean",fetch=FetchType.LAZY)
#JsonIgnore
private Set<ClientDetail> clientDetails;
//bi-directional many-to-one association to Company
#OneToMany(mappedBy="address", fetch=FetchType.LAZY)
#JsonIgnore
private Set<Company> companies;
}