I've been trying to solve this thing for along time now, but I haven't gotten anywhere. I've been trying to save a entity that posses a reference to another entity.
User creates an place entity by filling out the form then presses save to save it. It should automatically make new rows into 'places' and 'place_urls' tables. Here is a link to SQL file that I'm loading into the application: https://pastebin.com/x8Gvk7ub
Parent entity:
#Entity
#Table(name="places")
public class Place {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable=false, updatable=false)
private Long id;
#Column(name="userId")
private Long userId;
#Column(name="name", nullable=false, unique=true)
private String name;
#Column(name="address", nullable=false)
private String address;
#Column(name="largeDescription", nullable=false)
private String largeDescription;
#Column(name="smallDescription", nullable=false)
private String smallDescription;
#OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name="id")
private PlaceUrl placeUrl;
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name="id")
private List<Booking> bookings;
getters and setters...
}
Child entity:
#Entity
#Table(name="placeUrls")
public class PlaceUrl {
#Id
#Column(name="id", nullable=false, updatable=false)
private Long id;
#Column(name="placeId", nullable=false, updatable=false)
private Long placeId;
#Column(name="url", nullable=false, updatable=true, unique=true)
private String url;
#OneToOne
#JoinColumn(name="id", referencedColumnName="placeId")
private Place place;
getters and setters...
}
Controller:
#PostMapping("/place/add")
public String addPlace(#ModelAttribute Place place, #AuthenticationPrincipal UserDetails currentUser) {
User user = userRepository.findUserByUsername(currentUser.getUsername());
place.setUserId(user.getId());
placeRepository.save(place);
return "redirect:/places";
}
Hibernate naming is set to implicitic-strategy in application.properties
UPDATE:
Place entity:
#OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="place")
private PlaceUrl placeUrl;
PlaceUrl entity:
Removed the placeId column, placeId variable and it's getters and setters.
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="placeId")
private Place place;
Controller changes:
#PostMapping("/place/add")
public String addPlace(#ModelAttribute Place place, #AuthenticationPrincipal UserDetails currentUser) {
User user = userRepository.findUserByUsername(currentUser.getUsername());
place.setUserId(user.getId());
place.getPlaceUrl().setUrl("something_nice");
placeRepository.save(place);
return "redirect:/places";
}
Now upon save I get: No message available java.lang.NullPointerException
UPDATE 2:
I got working by just messing around. I have no idea why it works, so someone else can explain.
#PostMapping("/place/add")
public String addPlace(Model model, #ModelAttribute Place place, #AuthenticationPrincipal UserDetails currentUser) {
PlaceUrl placeUrl = new PlaceUrl();
User user = userRepository.findUserByUsername(currentUser.getUsername());
placeUrl.setUrl(place.getName());
place.setPlaceUrl(placeUrl);
place.setUserId(user.getId());
placeUrl.setPlace(place); <-- this line here made it all work
placeRepository.save(place);
return "redirect:/places";
}
I followed the instructions of the guide book that I was suggested. Basically I added #OneToOne(mappedBy="place") to the parent then I added #OneToOne and #JoinColumn(name="placeId") to the child entity.
You're already mapping the relationship in parent entity but not using it in child. Instead, by defining another mapping, you cannot take advantage of cascading. The solution would be to add mappedBy in PlaceUrl:
#OneToOne(mappedBy = "placeUrl")
private Place place;
Or even better, use mappedBy on the child side, which is the clean approach.
Related
I'm trying to map those three entities to each other without adding any additional fields to any of them. They should only contain the fields that already exist. I'm also trying to only get columns in the tables that represent the currently existing entity fields- and no additional columns.
#Entity
public class Order {
#Id
private Integer orderId;
private String title;
private Customer customer;
private List<Comment> comments;
}
#Entity
public class Customer {
#Id
private Integer customerId;
private String name;
}
#Entity
public class Comment {
#Id
private Integer commentId;
private Integer orderId;
private String details;
}
My understanding is that I can't simply use #OneToOne, #OneToMany and #ManyToOne mappings, because neither Customer nor Comment has a reference to Order . I'm trying to somehow reference the ids of Customer and Comment directly from Order.
I've tried using #MapsId and #JoinColumn but either I don't know how to properly use them, or they don't do what I think they do.
Is this task at all possible? If so, how to map them to each other?
For the reference to Comment you must use #JoinColum
The Customer reference assumes that there is a customer_id on the order table.
#Entity
public class Order {
#Id
private Integer orderId;
private String title;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
#OneToMany
#JoinColumn(name = "comment_id")
private List<Comment> comments;
}
I am working a very small application which contains 3 entity classes.
1.Category.
2.Products.
3.User
Relationships:-
a. OneToMany between User and Products.
b. OneToMany and ManyToOne between category and products i.e. a category can have multiple products and multiple products can belong to same category.
Entity Classes are shown below:-
User Entity:-
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String lastname;
private String email;
private String password;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.EAGER)
private Set<Products> products;
//getter and setter
}
Products Entity:-
#Entity
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String productname;
private String cost;
#ManyToOne(cascade = {CascadeType.MERGE,CascadeType.PERSIST},
fetch = FetchType.LAZY)
private Category category;
//getter and setters
}
Category Entity:-
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#OneToMany(mappedBy = "category",
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.EAGER)
private List<Products> products;
//getter and setters
}
Method to merge User with products in data base:-
#GetMapping("/cart")
public String Cart(Model model){
model.addAttribute("cart",productsSet);
System.out.println(productsSet);//At this stage in console I am able to see products added in set
User user = userRepository.findById(1);//hard coded for now.
user.setProducts(productsSet);
userService.saveUserProducts(user);//saveUserProducts() method in shown below.
productsSet.clear();
return "mycart";
}
saveUserProducts() :-
#Override
#Transactional
public void saveUserProducts(User user) {
entityManager.merge(user);
}
But when I am running the program I see the following exception in console:-
java.lang.IllegalStateException: Multiple representations of the same entity [com.demo.shopping.com.Entity.Products#2] are being merged. Detached: [Products{id=2, productname='p2', cost='200'}]; Detached: [Products{id=2, productname='p2', cost='200'}]
I found an article on stack-overflow but it was not fit in my situation.(java.lang.IllegalStateException: Multiple representations of the same entity with #ManyToMany 3 entities).Except this I don't get any relevant thing.
Please help me to let me know how to deal with this situation. Hope someone will help.
Thanks in advance.
Remove CascadeType.MERGE user class because in my program I am not adding new products also except this I am creating relation between existing user and products.
i am new in spring boot and i could not find solution for this for a day now.
#GetMapping used to retrive item gives a responce of infinite loop of foreignkey object "user".
why am i getting this infinite loop?
how to fix it?
user object in infinite loop(the problem)
result that i want
item entity
#Entity
public class Item{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ItemId;
#ManyToOne
#JoinColumn(name = "owner_id")
private User user;
private String ItemName;
// #Column(columnDefinition="text")
private String Description;
private double Price;
private int AvailableQuantity;
private double shippingWeight;
// #Transient
// private MultipartFile Picture;
#Enumerated(value = EnumType.STRING)
private Category category;
#OneToMany(mappedBy = "item")
#JsonIgnore
private List<CartItem> CartItemList;
}
user entity
#Entity
#Table(name = "Utilisateur")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idU;
private String username;
private String password;
private String firstname;
private String lastname;
private String gender;
private Long phone;
private String adress;
#Temporal(TemporalType.DATE)
private Date dateofbirth;
private int rating;
private String email;
public Role role;
private Integer status;
#OneToMany(mappedBy = "user")
private List<Item> ItemList;
}
item service
#Service
public class ItemService implements ItemServiceInterface{
#Autowired
ItemRepository itemrepository;
public Optional<Item> getItemById(long id){
return itemrepository.findById(id);
}
}
item controller
#RestController
public class ItemControl {
#Autowired
ItemServiceInterface itemservice;
#GetMapping("/getitem/{id}")
public Optional<Item> getitembyid(#PathVariable Long id) {
return itemservice.getItemById(id);
}
}
You can use combination of #JsonManagedReference and #JsonBackReference to discourage Jackson from infinite serialization.
#Entity
#Table(name = "Utilisateur")
public class User {
// omitted
#JsonManagedReference
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Item> ItemList;
}
#Entity
public class Item{
// omitted
#JsonBackReference
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "owner_id")
private User user;
}
More details could be found here https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
You can make use of lazy loading to cut the dependency loop between user and item. However, following that approach might potentially affect other parts of your projects because other codes might use the entity with an assumption that item list in user entity is already eager fetched.
A better way is not return the entity object directly to the REST response. You can define a data model for the rest response and convert the entity to that model in your service class. This way, you can completely control what to return and not to.
Another approach if you still want to use the entity as response: https://www.baeldung.com/spring-data-jpa-named-entity-graphs. This way, you can define when to use the lazy load with each specific query.
I can't make my foreign keys auto generate using hibernate and jpa with annotations. Everything seems ok, The entries are saved in database. All the date come from one form which, when submited creates an User object with ModelAttribute and then saves it in Database.
Here are my beans. Anything else i should add ?
#Entity
#Table(name="adress")
public class Adress implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="adress_id")
private Integer adressId;
#NotBlank(message="The city must be completed")
#Column(name="city")
#Size(min=5,max=30)
private String city;
#NotBlank(message="The street must be completed")
#Column(name="street")
#Size(min=5,max=30)
private String street;
#NotNull(message="The street number must be completed")
#NumberFormat
#Column(name="street_no")
private Integer streetNo;
#OneToOne
#JoinColumn(name="user_id")
private User user;}
and the other one:
#Entity
#Table(name="users")
public class User implements Serializable {
#Id
#Column(name="user_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;
#NotBlank(message="Username can't be blank")
#Size(min=5,max=30)
#Column(name="username")
private String username;
#NotBlank(message="Password field can't be blank")
#Size(min=5,max=30)
#Column(name="password")
private String password;
#NumberFormat
#NotNull(message="Age field must not be blank")
#Column(name="age")
private Integer age;
#Column(name="message")
#Size(min=0,max=100)
private String message;
#Column(name="date")
#DateTimeFormat(pattern="dd/mm/yyyy")
private Date dateCreated;
#OneToOne(mappedBy="user",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Adress adress;
+getters and setters for them
public void save(T entity){
sessionFactory.getCurrentSession().save(entity);
}
If I understand you correctly and you're trying to get Hibernate to set the foreign key on your related record this might help. Try getting rid of mappedBy and instead specify the JoinColumn. This works for me on a one to many:
The order:
#Entity
#Table(name = "`order`")
public class Order implements Serializable {
#Id
#GeneratedValue
private Long id;
// Order columns...
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id")
private Set<Item> items;
}
The item:
#Entity
#Table(name = "item")
public class Item implements Serializable {
#Id
#GeneratedValue
private Long id;
// Item columns...
#ManyToOne(optional = false)
#JoinColumn(name = "order_id", referencedColumnName = "id", nullable = false)
private Order order;
}
in adress class
#OneToOne(mappedBy="adress")
private User user;
and in user class
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER,optional=false)
#PrimaryKeyJoinColumn
private Adress adress;
OK, so I've designed a basic CRUD an an exercise. It has 2 tables Jobs and Employees. I'm trying to create a many to one relationship, but when I click the link to go to the Employee Entry page it throws an error that kicks off with the #ManyToOne referencing an Unknown Entity.
Here is what I've got in my Employees.java
String jobName;
#ManyToOne(fetch=FetchType.EAGER)
#Fetch(value = FetchMode.JOIN)
#JoinColumn(name = "Job_Name")
#Column (name='jobName')
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
Any idea what i"m doing wrong and how to resolve this?
As per your comment,i think you can define relationship between these two entities like below.
#Entity
#Table(name="employee")
class Employee{
#Id
#GeneratedValue
private Integer id;
#ManyToOne
#JoinColumn(name = "job_name")
private Job job;
// other column and getter and setter
}
#Entity
#Table(name="job")
class Job{
#Id
#GeneratedValue
private Integer id;
#Column(name="job_name")
private String jobName;
//provide other column and getter setter
}