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
}
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 trying to save a JPA entity which has ManytoMany Relationship (Consumer and Product table) and OnetoOne relation with ConsumerDetailstable.Below are my entities
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
#Entity
public class Consumer {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
#JsonManagedReference
#OnToMany(mappedBy = "consumer")
private Set<ConsumerProduct> consumerProducts;
#OneToOne
private CustomerDetails consumerDetails;
}
#Entity
public class Product {
#Id
#GeneratedValue
private Long productId;
private String productCode;
#OneToMany(mappedBy = "product")
private Set<ConsumerProduct> consumerProducts;
}
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class)
#Entity(the join table)
public class ConsumerProduct {
#EmbeddedId
ConsumerProductKey id;
#JsonBackReference
#ManyToOne
#MapsId("id")
#JoinColumn(name = "id")
private Consumer consumer;
#ManyToOne
#MapsId("productId")
#JoinColumn(name = "product_id")
private Product product;
}
#Embeddable (forgein keys combined as embeded id)
public class ConsumerProductKey implements Serializable {
#Column(name="id")
private Long id;
#Column(name = "product_id")
private Long productId;
}
#Enitity (one to one relation table)
public class CustomerDetails {
#Id
#GeneratedValue
private Long consumerDtlId;
#OneToOne
private Consumer consumer;
private String city;
private String state;
private String country;
}
To save the entity am have just extended JPARepository and called save method
public class ConsumerRepository<Consumer> Implements JPARepository<Consumer, Long> {
#Override
public Consumer S save(Consumer entity) {
return save(entity);
};
}
I get java.lang.StackOverFlowError at save method.
Anything wrong with my Mappings ?
Question: Since this will be save operation and since Consumer Id is yet to be generated how do I assign to below Entities
ConsumerProduct.ConsumerProductKey (how do i assign Id of consumer table once it is inserted to join table ? will JPA take care of it)
CustomerDetails (how do i assign Id of consumer table once it is inserted to join table ? will JPA take care of it)
EDIT: I have updated the entity with JsonManagedReference and JsonBackedReference but still i have am facing stackoverflow error
It is due to Consumer trying to access ConsumerProduct and ConsumerProduct trying to access consumer entity and end up with StackOverflow error.
You should use #JsonManagedReference and #JsonBackReference annotation in consumer and ConsumerProduct respectivly.
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.
I am learning Hibernate ....
#Id
#GeneratedValue(generator="foreign")
#GenericGenerator(name="foreign", strategy="foreign", parameters={
#Parameter(name="property" ,value="company")
})
public Long getId() {
return id;
}
In the above code i understand most of the things except these lines
parameters={
#Parameter(name="property" ,value="company")
}
Please help
For every GenericGenerator, you can pass a list of key/value (parameters) regarding your strategy.
A GenericGenerator using the strategy "foreign" expects one parameter called "property" and the expected value is an entity name. This means your entity's ID will be the same as the linked entity.
For example:
Author entity:
#Entity
#Table(name="authors")
public class Author {
#Id
#GeneratedValue
private Integer id;
private String name;
#OneToOne(mappedBy="author", cascade=CascadeType.ALL)
private Biography biography;
}
Biography entity:
#Entity
#Table(name="biographies")
public class Biography {
#Id
#Column(name="id")
#GeneratedValue(generator="gen")
#GenericGenerator(name="gen", strategy="foreign",
parameters=#Parameter(name="property", value="author"))
private Integer id;
#OneToOne
#PrimaryKeyJoinColumn
private Author author;
}
In that case, every Biography ID will have the same ID as the Author's ID.
I have such a simple scheme
and the following entities:
#Entity
public class Ticket {
#Id
#GeneratedValue
private Integer id;
#ManyToOne
private Event event;
#OneToOne
private User user;
#Embedded
private Seat seat;
private TicketState state;
private Float price;
// getters, setters, etc.
#Entity
public class Event {
#Id
#GeneratedValue
private Integer id;
#OneToOne
private Movie movie;
#Embedded
private Auditorium auditorium;
private LocalDateTime startDateTime;
#OneToMany
private Set<Ticket> tickets = new HashSet<>();
// getters, setters, etc.
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
#Enumerated(EnumType.STRING)
private UserRole role;
private String name;
private String email;
private Instant birthday;
#OneToMany
private List<Ticket> tickets = new ArrayList<>();
private boolean lucky;
// getters, setters, etc.
#Embeddable
public class Auditorium {
private Integer id;
private String name;
private Integer seatsNumber;
#ElementCollection
private List<Integer> vipSeats;
// getters, setters, etc.
Also these entities was added to hibernate.cfg.xml.
Than I run app I have the following exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.epam.spring.core.domain.Event column: id (should be mapped with insert="false" update="false")
At first glance I don't see any duplications in Event, as mentioned in exception. What should I fix in entities mapping description to resolve the problem according my scheme? Thank you!
Both Event and Auditorium map to column named id.
Specify a different column name in Auditorium or use #AttributeOverride in Event to override the default name.
When you map an entity with annotations, you do not need to repeat yourself on hibernate.cfg.xml. Try to delete it e run your code again.
Updating my answer based on Dragan Bozanovic's, Auditorium should NOT have an #Id annotated field (but we can't see that from your code, if it has).