Help me to understand how I can realize many to many self join with extra column using hibernate? Should I map join table too? Or may be exists another way? I can not find anything usefull for me...
Map the join table as a dedicated entity and then link it via two OneToMany relationships. This often is the right way as it becomes more than just a technical detail as soon as you add more columns.
This should work the same way for a self join, you just have two fields on that model that are associated to the joining entity.
See this answer, where this is described in more detail.
I've been struggling with this question for a long time, perhaps someone will find Wolfram's wording difficult, so I'll explain it in more detail:
Imagine, what we need map something like that uml_diagramm
I needed to set up links between any two users, and the links were used to chat between them. So our user class will be :
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
#Entity
public class User implements Serializable {
private String email;
private String password;
private Long id;
private String nickname;
private String phone;
private Collection<Chats> chatsById;
private Collection<Chats> chatsById_0;
#Basic
#Column(name = "email", nullable = false, length = -1)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Basic
#Column(name = "password", nullable = false, length = -1)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Id
#Column(name = "id", nullable = false)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Basic
#Column(name = "nickname", nullable = true, length = -1)
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
#Basic
#Column(name = "phone", nullable = true, length = -1)
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(email, user.email) && Objects.equals(password, user.password) && Objects.equals(id, user.id) && Objects.equals(nickname, user.nickname) && Objects.equals(phone, user.phone);
}
#Override
public int hashCode() {
return Objects.hash(email, password, id, nickname, phone);
}
#OneToMany(mappedBy = "userByIdFrom")
public Collection<Chats> getChatsById() {
return chatsById;
}
public void setChatsById(Collection<Chats> chatsById) {
this.chatsById = chatsById;
}
#OneToMany(mappedBy = "userByIdTo")
public Collection<Chats> getChatsById_0() {
return chatsById_0;
}
public void setChatsById_0(Collection<Chats> chatsById_0) {
this.chatsById_0 = chatsById_0;
}
}
Please, pay attention to two #OneToMany annotations - getChatsById and getChatsById_0
Now our Chat class:
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
#Entity
#IdClass(ChatsPK.class)
public class Chats implements Serializable {
private Long idFrom;
private Long idTo;
private Object uuid;
private User userByIdFrom;
private User userByIdTo;
#Id
#Column(name = "id_from", nullable = false)
public Long getIdFrom() {
return idFrom;
}
public void setIdFrom(Long idFrom) {
this.idFrom = idFrom;
}
#Id
#Column(name = "id_to", nullable = false)
public Long getIdTo() {
return idTo;
}
public void setIdTo(Long idTo) {
this.idTo = idTo;
}
#Basic
#Column(name = "uuid", nullable = false)
public Object getUuid() {
return uuid;
}
public void setUuid(Object uuid) {
this.uuid = uuid;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Chats chats = (Chats) o;
return Objects.equals(idFrom, chats.idFrom) && Objects.equals(idTo, chats.idTo) && Objects.equals(uuid, chats.uuid);
}
#Override
public int hashCode() {
return Objects.hash(idFrom, idTo, uuid);
}
#ManyToOne
#JoinColumn(name = "id_from", referencedColumnName = "id", nullable = false)
public User getUserByIdFrom() {
return userByIdFrom;
}
public void setUserByIdFrom(User userByIdFrom) {
this.userByIdFrom = userByIdFrom;
}
#ManyToOne
#JoinColumn(name = "id_to", referencedColumnName = "id", nullable = false)
public User getUserByIdTo() {
return userByIdTo;
}
public void setUserByIdTo(User userByIdTo) {
this.userByIdTo = userByIdTo;
}
}
To be honest, I haven't figured out why it works yet myself
but, there should be more details
Meanwhile, I know for a fact that intelijIdea can generate you models from the database and this may be help you Generate Persistence Mapping by Database Schema - Detail settings for Entity Class. (This code was generated by it )
Related
I am trying to create a TableView in JavaFX, but after many attempts values are not showing without giving any Errors.
If i create a TableView with only one Object declared (TableView) it works properly.
I already tried to create a "helper" class, which contained both objects as it's attributes, but still the same problem no errors just TableView not working.
Any suggestions how to fix this?
Here is what i am trying to do:
public TableColumn<CarEntity, String> HistoryBrand;
public TableColumn<CarEntity, String> HistoryColor;
public TableColumn<CarEntity, Date> HistoryDate;
public TableColumn<CarEntity,String> HistoryCategory;
public TableColumn<CarEntity,Double> HistoryPrice;
public TableColumn<OrdersArchiveEntity, Integer> HistoryCarScore;
public TableColumn<OrdersArchiveEntity, Integer> HistoryOrderScore;
public TableColumn<OrdersArchiveEntity, Date> HistoryRentalDate;
public TableColumn<OrdersArchiveEntity, Date> HistoryReturnDate;
public TableView HistoryTable;
HistoryBrand.setCellValueFactory(new PropertyValueFactory<CarEntity, String>("mark"));
HistoryColor.setCellValueFactory(new PropertyValueFactory<CarEntity,String>("color"));
HistoryDate.setCellValueFactory(new PropertyValueFactory<CarEntity, Date>("productionDate"));
HistoryCategory.setCellValueFactory(new PropertyValueFactory<CarEntity, String>("category"));
HistoryPrice.setCellValueFactory(new PropertyValueFactory<CarEntity, Double>("price"));
HistoryCarScore.setCellValueFactory(new PropertyValueFactory<OrdersArchiveEntity,Integer>("carScore"));
HistoryOrderScore.setCellValueFactory(new PropertyValueFactory<OrdersArchiveEntity,Integer>("orderScore"));
HistoryRentalDate.setCellValueFactory(new PropertyValueFactory<OrdersArchiveEntity,Date>("rentalDate"));
HistoryReturnDate.setCellValueFactory(new PropertyValueFactory<OrdersArchiveEntity,Date>("returnDate"));
Query queryHist = session.createQuery("select c, o from OrdersArchiveEntity o, CarEntity c where c.id=o.carByCarId.id");
List HistoryList = queryHist.list();
ObservableList Historia = FXCollections.observableArrayList(HistoryList);
HistoryTable.setItems(Historia);
And here are my Classes
package DataBase;
import javax.persistence.*;
import java.sql.Date;
import java.util.Objects;
#Entity
#Table(name = "Car", schema = "dbo", catalog = "master")
public class CarEntity {
private int id;
private RentalBaseEntity RentalBaseEntityByRentalBaseId;
public String mark;
public String color;
public Date productionDate;
public double price;
private String category;
#Id
#Column(name = "ID", nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "Mark", nullable = false, length = 20)
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
#Basic
#Column(name = "Color", nullable = false, length = 20)
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
#Basic
#Column(name = "Production_Date", nullable = false)
public Date getProductionDate() {
return productionDate;
}
public void setProductionDate(Date productionDate) {
this.productionDate = productionDate;
}
#Basic
#Column(name = "Price", nullable = false, precision = 0)
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
#Basic
#Column(name = "Category", nullable = false, length = 20)
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CarEntity carEntity = (CarEntity) o;
return id == carEntity.id &&
Double.compare(carEntity.price, price) == 0 &&
Objects.equals(mark, carEntity.mark) &&
Objects.equals(color, carEntity.color) &&
Objects.equals(productionDate, carEntity.productionDate) &&
Objects.equals(category, carEntity.category);
}
#Override
public int hashCode() {
return Objects.hash(id, mark, color, productionDate, price, category);
}
#ManyToOne
#JoinColumn(name = "RentalBase_Id", referencedColumnName = "ID", nullable = false)
public RentalBaseEntity getRentalBaseEntityByRentalBaseId() {
return RentalBaseEntityByRentalBaseId;
}
public void setRentalBaseEntityByRentalBaseId(RentalBaseEntity here) {
this.RentalBaseEntityByRentalBaseId = here;
}
}
package DataBase;
import javax.persistence.*;
import java.sql.Date;
import java.util.Objects;
#Entity
#Table(name = "OrdersArchive", schema = "dbo", catalog = "master")
public class OrdersArchiveEntity {
private int id;
private int orderScore;
private int carScore;
private Date rentalDate;
private Date returnDate;
private CarEntity carByCarId;
private SellerEntity sellerBySellerId;
private ClientEntity clientByClientId;
private RentalBaseEntity RentalBaseEntitybyID;
private int Orders_Id;
#Id
#Column(name = "ID", nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "Order_Score", nullable = false)
public int getOrderScore() {
return orderScore;
}
public void setOrderScore(int orderScore) {
this.orderScore = orderScore;
}
#Basic
#Column(name = "Orders_Id", nullable = false)
public int getOrders_Id() {
return Orders_Id;
}
public void setOrders_Id(int Orders_Id) {
this.Orders_Id = Orders_Id;
}
#Basic
#Column(name = "Car_Score", nullable = false)
public int getCarScore() {
return carScore;
}
public void setCarScore(int carScore) {
this.carScore = carScore;
}
#Basic
#Column(name = "Rental_Date", nullable = false)
public Date getRentalDate() {
return rentalDate;
}
public void setRentalDate(Date rentalDate) {
this.rentalDate = rentalDate;
}
#Basic
#Column(name = "Return_Date", nullable = false)
public Date getReturnDate() {
return returnDate;
}
public void setReturnDate(Date returnDate) {
this.returnDate = returnDate;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrdersArchiveEntity that = (OrdersArchiveEntity) o;
return id == that.id &&
orderScore == that.orderScore &&
carScore == that.carScore && Objects.equals(rentalDate, that.rentalDate) &&
Objects.equals(returnDate, that.returnDate) ;
}
#Override
public int hashCode() {
return Objects.hash(id, orderScore, carScore, rentalDate, returnDate);
}
#ManyToOne
#JoinColumn(name = "id_Base", referencedColumnName = "ID", nullable = false)
public RentalBaseEntity getRentalBaseEntitybyID() {
return RentalBaseEntitybyID;
}
public void setRentalBaseEntitybyID(RentalBaseEntity RentalBaseEntitybyID) {
this.RentalBaseEntitybyID = RentalBaseEntitybyID;
}
#ManyToOne
#JoinColumn(name = "Car_Id", referencedColumnName = "ID", nullable = false)
public CarEntity getCarByCarId() {
return carByCarId;
}
public void setCarByCarId(CarEntity carByCarId) {
this.carByCarId = carByCarId;
}
#ManyToOne
#JoinColumn(name = "Seller_Id", referencedColumnName = "ID")
public SellerEntity getSellerBySellerId() {
return sellerBySellerId;
}
public void setSellerBySellerId(SellerEntity sellerBySellerId) {
this.sellerBySellerId = sellerBySellerId;
}
#ManyToOne
#JoinColumn(name = "Client_Id", referencedColumnName = "ID", nullable = false)
public ClientEntity getClientByClientId() {
return clientByClientId;
}
public void setClientByClientId(ClientEntity clientByClientId) {
this.clientByClientId = clientByClientId;
}
}
I have these entities
NormalizedChannelStock.java
#Entity
#Table(name = "stocks")
public class NormalizedChannelStock {
#EmbeddedId
private NormalizedChannelStockId id;
#Column(name = "qty")
private int qty;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "channel_id", insertable = false, updatable = false)
private Channel channel;
#Column(name = "created_at", updatable = false)
private Timestamp createdAt;
#Column(name = "updated_at", updatable = false)
private Timestamp updatedAt;
public NormalizedChannelStockId getId() {
return id;
}
public void setId(NormalizedChannelStockId id) {
this.id = id;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public Timestamp getCreatedAt() {
return createdAt;
}
public Timestamp getUpdatedAt() {
return updatedAt;
}
}
NormalizedChannelStockId.java
#Embeddable
public class NormalizedChannelStockId implements Serializable {
#Column(name = "channel_id")
private Integer channelId;
#Column(name = "sku")
private String sku;
public NormalizedChannelStockId() {
}
public NormalizedChannelStockId(Integer channelId, String sku) {
this.channelId = channelId;
this.sku = sku;
}
public Integer getChannelId() {
return channelId;
}
public void setChannelId(Integer channelId) {
this.channelId = channelId;
}
public String getSku() {
return sku;
}
public void setSku(String sku) {
this.sku = sku;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NormalizedChannelStockId that = (NormalizedChannelStockId) o;
return channelId.equals(that.channelId) &&
sku.equals(that.sku);
}
#Override
public int hashCode() {
return Objects.hash(channelId, sku);
}
}
Channel.java
#Entity
#Table(name = "channels")
public class Channel {
#Id
#Column(name = "channel_id")
private int channelId;
#Column(name = "channel_name")
private String channelName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "store_id", insertable = false, updatable = false)
private Store store;
public int getChannelId() {
return channelId;
}
public void setChannelId(int channelId) {
this.channelId = channelId;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public Store getStore() {
return store;
}
public void setStore(Store store) {
this.store = store;
}
}
The problem I'm facing is when I call
List<NormalizedChannelStock> entitiesToSave = ...
List<NormalizedChannelStock> savedEntities = normalizedChannelStockService.saveAll(entitiesToSave);
The returned entities in savedEntities have their Channel inner objects set to null, as well as their created_at and updated_at as shown
Is this normal behaviour? When I run a findAllById on the Repository, the Channels inside the Entities are loaded lazily properly, so I believe the entities are properly mapped in code. The problem is after I save them.
Does JPA not reload the entity after saving it?
As you stated in the comments you did not set those values before saving.
JPA does not load them for you. JPA pretty much doesn't load anything upon saving except the id if it is generated by the database.
A more common case of the same problem/limitation/misconceptions are bidirectional relationships: JPA pretty much ignores the not owning side and the developer has to make sure that both sides are in sync at all times.
You would have to refresh the entity yourself. Note that just loading it in the same transaction would have no effect because it would come from the 1st level cache and would be exactly the same instance.
I'm working on a rest project using Spring Boot and Hibernate and am currently trying to figure out how to handle my json-serialization.
The schema shown in the ERD above is mapped by Hibernate and works fine.
The problem arises when I make a get request to a controller. My understanding is that Spring now tries to serialize the object-chain using Jackson. Because both the parent and child objects have one another as an attribute, we find ourselves hitting an infinite recursion loop.
Now I've looked into #JsonIgnore, #JsonView, #JsonManagedReference and #JsonBackReference but these only seem to work for one-to-many relationships.
What I'm looking for is a situation where when I for instance make a GET request to /users/{id}, I get the user object including all it's relationship attributes (let's call it the full object), but the relationship attributes themselves don't show their relationship-attributes (minimized objects). This works fine with the annotations mentioned above, but how do I make this work the other way as well?
Desired response for: /users/{id}
{ // full user object
id: 1,
username: 'foo',
// password can be JsonIgnored because of obvious reasons
role: { // minimized role object
id: 1,
name: 'bar'
// NO USERS LIST
}
area: { //minimized area object
id: 2,
name: 'some val'
// NO USERS LIST
// NO TABLES LIST
}
}
Desired response for /userrole/{id}
{ // full role object
id: 1,
name: 'waiter'
users: [
{ // minmized user object
id: 1,
username: 'foo'
// password can be JsonIgnored because of obvious reasons
// NO ROLE OBJECT
// NO AREA OBJECT
},
{ // minmized user object
id: 1,
username: 'foo'
// password can be JsonIgnored because of obvious reasons
// NO ROLE OBJECT
// NO AREA OBJECT
}
]
}
In general: I'd like a full object when the request is made to the entity directly and a minimized object when requested indirectly.
Any Ideas? I hope my explanation is clear enough.
UPDATE
The Area, User and UserRole POJO's as requested in the comment sections.
User
#Entity
#Table(name = "users", schema = "public", catalog = "PocketOrder")
public class User {
private int id;
private String username;
private String psswrd;
private List<Area> areas;
private UserRole Role;
#Id
#Column(name = "id", nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "username", nullable = false, length = 20)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Basic
#JsonIgnore
#Column(name = "psswrd", nullable = true, length = 40)
public String getPsswrd() {
return psswrd;
}
public void setPsswrd(String psswrd) {
this.psswrd = psswrd;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (id != user.id) return false;
if (username != null ? !username.equals(user.username) : user.username != null) return false;
if (psswrd != null ? !psswrd.equals(user.psswrd) : user.psswrd != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (username != null ? username.hashCode() : 0);
result = 31 * result + (psswrd != null ? psswrd.hashCode() : 0);
return result;
}
#ManyToMany(mappedBy = "users")
public List<Area> getAreas() {
return areas;
}
public void setAreas(List<Area> areas) {
this.areas = areas;
}
#ManyToOne
#JoinColumn(name = "role_fk", referencedColumnName = "id", nullable = false)
public UserRole getRole() {
return Role;
}
public void setRole(UserRole role) {
Role = role;
}
}
UserRole
#Entity
#javax.persistence.Table(name = "userroles", schema = "public", catalog = "PocketOrder")
public class UserRole {
private int id;
private String name;
private List<User> users;
#Id
#Column(name = "id", nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = false, length = 20)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserRole userRole = (UserRole) o;
if (id != userRole.id) return false;
if (name != null ? !name.equals(userRole.name) : userRole.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
#OneToMany(mappedBy = "role")
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
users = users;
}
}
Area
#Entity
#javax.persistence.Table(name = "areas", schema = "public", catalog = "PocketOrder")
public class Area {
private int id;
private String name;
private List<User> users;
private List<Table> tables;
#Id
#Column(name = "id", nullable = false)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Basic
#Column(name = "name", nullable = false, length = 20)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Area area = (Area) o;
if (id != area.id) return false;
if (name != null ? !name.equals(area.name) : area.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
#ManyToMany
#JoinTable(name = "areas_users", catalog = "PocketOrder", schema = "public", joinColumns = #JoinColumn(name = "area_fk", referencedColumnName = "id", nullable = false), inverseJoinColumns = #JoinColumn(name = "user_fk", referencedColumnName = "id", nullable = false))
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
#OneToMany(mappedBy = "area")
public List<Table> getTables() {
return tables;
}
public void setTables(List<Table> tables) {
this.tables = tables;
}
}
Try use #JsonSerialize on specific points:
For sample:
1 - Map your field
#JsonSerialize(using = ExampleSampleSerializer.class)
#ManyToOne
private Example example;
2 - Create custom jackson serializer (Here you can control the serialization)
public class ExampleSampleSerializer extends JsonSerializer<Example> {
#Override
public void serialize(Example value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException, JsonProcessingException {
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("first");
jsonGenerator.writeNumber(value.getFirstValue());
jsonGenerator.writeFieldName("second");
jsonGenerator.writeNumber(value.getSecondValue());
jsonGenerator.writeFieldName("third");
jsonGenerator.writeNumber(value.getAnyAnotherClass().getThirdValue());
jsonGenerator.writeEndObject();
}
}
The way I worked around this on a Many-to-Many relationship is by using
#JsonIgnore
On one of the Entities.
For example we have Person and Child entities. One Person can have many children and vice-versa.
On Person we have :
public class Person
{
//Other fields ommited
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "person_child",
joinColumns = {
#JoinColumn(name = "person_id", referencedColumnName = "id", nullable = false,
updatable = false)
},
inverseJoinColumns = {
#JoinColumn(name = "child_id", referencedColumnName = "id", nullable =
false, updatable = false)
})
private Set<Child> children = new HashSet<>() ;
}
And on Child we have :
public class Child
{
#JsonIgnore
#ManyToMany(mappedBy = "children", fetch = FetchType.LAZY)
private Set<Person> people = new HashSet<>() ;
}
Now when we get a Person, we also get all his connected children. But when we get a Child then we don't get all People because we have #JsonIgnore annotation on it.
This fixes the Infinite Recursion problem, and raises this one.
My workaround was by writing a query to get me all the People connected to a specific child_id.
Below you may see my code:
public interface PersonDAO extends JpaRepository<Person, Long>
{
#Query(value = "SELECT * " +
" FROM person p INNER JOIN person_child j " +
"ON p.id = j.person_id WHERE j.child_id = ?1 ", nativeQuery = true)
public List<Person> getPeopleViaChildId(long id);
}
And i use it whenever I want to get all People from a child.
this is my first post, so please bear with me if i do make any errors.
I get an error " java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST"
whenever i want to query(add,edit,delete) the database.
The tables related are sponsors and donations. There is a one to many relationship between them. Classes below:
Sponsors
#Entity
#Table(name = "SPONSORS")
#NamedQueries({
#NamedQuery(name = "Sponsors.findAll", query = "SELECT s FROM Sponsors s")})
public class Sponsors implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "SPONSORID")
private Short sponsorid;
#Basic(optional = false)
#Column(name = "NAME")
private String name;
#Basic(optional = false)
#Column(name = "SURNAME")
private String surname;
#Basic(optional = false)
#Column(name = "ADDRESS")
private String address;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "sponsorid")
private List<Donations> donationsList;
public Sponsors() {
}
public Sponsors(Short sponsorid) {
this.sponsorid = sponsorid;
}
public Sponsors(Short sponsorid, String name, String surname, String address) {
this.sponsorid = sponsorid;
this.name = name;
this.surname = surname;
this.address = address;
}
public Short getSponsorid() {
return sponsorid;
}
public void setSponsorid(Short sponsorid) {
this.sponsorid = sponsorid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Donations> getDonationsList() {
return donationsList;
}
public void setDonationsList(List<Donations> donationsList) {
this.donationsList = donationsList;
}
#Override
public int hashCode() {
int hash = 0;
hash += (sponsorid != null ? sponsorid.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Sponsors)) {
return false;
}
Sponsors other = (Sponsors) object;
if ((this.sponsorid == null && other.sponsorid != null) || (this.sponsorid != null && !this.sponsorid.equals(other.sponsorid))) {
return false;
}
return true;
}
#Override
public String toString() {
return "Pat.Sponsors[ sponsorid=" + sponsorid + " ]";
}
}
Donations:
#Entity
#Table(name = "DONATIONS")
#NamedQueries({
#NamedQuery(name = "Donations.findAll", query = "SELECT d FROM Donations d")})
public class Donations implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "DONATIONID")
private Short donationid;
#Basic(optional = false)
#Column(name = "DONATIONDATE")
#Temporal(TemporalType.DATE)
private Date donationdate;
// #Max(value=?) #Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
#Column(name = "DONATIONAMOUNT")
private Double donationamount;
#JoinColumn(name = "SPONSORID", referencedColumnName = "SPONSORID")
#ManyToOne(optional = false)
private Sponsors sponsorid;
public Donations() {
}
public Donations(Short donationid) {
this.donationid = donationid;
}
public Donations(Short donationid, Date donationdate) {
this.donationid = donationid;
this.donationdate = donationdate;
}
public Short getDonationid() {
return donationid;
}
public void setDonationid(Short donationid) {
this.donationid = donationid;
}
public Date getDonationdate() {
return donationdate;
}
public void setDonationdate(Date donationdate) {
this.donationdate = donationdate;
}
public Double getDonationamount() {
return donationamount;
}
public void setDonationamount(Double donationamount) {
this.donationamount = donationamount;
}
public Sponsors getSponsorid() {
return sponsorid;
}
public void setSponsorid(Sponsors sponsorid) {
this.sponsorid = sponsorid;
}
#Override
public int hashCode() {
int hash = 0;
hash += (donationid != null ? donationid.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Donations)) {
return false;
}
Donations other = (Donations) object;
if ((this.donationid == null && other.donationid != null) || (this.donationid != null && !this.donationid.equals(other.donationid))) {
return false;
}
return true;
}
#Override
public String toString() {
return "Pat.Donations[ donationid=" + donationid + " ]";
}
}
The field
#ManyToOne(optional = false)
private Sponsors sponsorid;
in the Donations entity is not configured for cascading. Try changing it to:
#ManuToOne(optional = false, cascade = CascadeType.ALL)
private Sponsors sponsorid;
I'm currently working on a small shop application for my School.
I have 2 objects I want to save :
Order.java
#Entity
#Table(name = "ORDERS")
public class Order {
private Integer id;
private Date orderDate;
private MailingAddress mailingAddress;
private User user;
private Collection<OrderLine> orderLines;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Basic
#Column(name = "ORDER_DATE")
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
#ManyToOne
#JoinColumn(name = "SHIPPING_ADR_ID", referencedColumnName = "ID")
public MailingAddress getMailingAddress() {
return mailingAddress;
}
public void setMailingAddress(MailingAddress mailingAddressByShippingAdrId) {
this.mailingAddress = mailingAddressByShippingAdrId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", referencedColumnName = "LOGIN")
public User getUser() {
return user;
}
public void setUser(User userByUserId) {
this.user = userByUserId;
}
#OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Collection<OrderLine> getOrderLines() {
return orderLines;
}
public void setOrderLines(Collection<OrderLine> orderLinesesById) {
this.orderLines = orderLinesesById;
}
}
OrderLine.java
#Entity
#Table(name = "ORDER_LINES", schema = "")
#IdClass(OrderLinesPK.class)
public class OrderLine {
private int quantity;
private Integer orderId;
private String bookId;
private Book book;
private Order order;
#Basic
#Column(name = "QUANTITY")
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
#Id
#Column(name = "ORDERS_ID", insertable = false, updatable = false)
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer ordersId) {
this.orderId = ordersId;
}
#Id
#Column(name = "BOOKS_ID", insertable = false, updatable = false)
public String getBookId() {
return bookId;
}
public void setBookId(String booksId) {
this.bookId = booksId;
}
#ManyToOne
#JoinColumn(name = "BOOKS_ID", referencedColumnName = "ISBN13", nullable = false, insertable = false, updatable = false)
public Book getBook() {
return book;
}
public void setBook(Book booksByBookId) {
this.book = booksByBookId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ORDERS_ID", referencedColumnName = "ID", nullable = false, insertable = false, updatable = false)
public Order getOrder() {
return order;
}
public void setOrder(Order ordersByOrderId) {
this.order = ordersByOrderId;
}
}
OrderLinesPK.java
public class OrderLinesPK implements Serializable {
private int ordersId;
private String booksId;
#Column(name = "ORDERS_ID")
#Id
public int getOrderId() {
return ordersId;
}
public void setOrderId(int ordersId) {
this.ordersId = ordersId;
}
#Column(name = "BOOKS_ID")
#Id
public String getBookId() {
return booksId;
}
public void setBookId(String booksId) {
this.booksId = booksId;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrderLinesPK that = (OrderLinesPK) o;
if (ordersId != that.ordersId) return false;
if (booksId != null ? !booksId.equals(that.booksId) : that.booksId != null) return false;
return true;
}
#Override
public int hashCode() {
int result = ordersId;
result = 31 * result + (booksId != null ? booksId.hashCode() : 0);
return result;
}
}
An order contains a collection of order lines.
I'm trying to save the order + the order lines in one call to OrderRepository.
But when I do that, I get the error
org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of edu.flst.bookstore.domaine.bo.OrderLinesPK.orderId
which is pretty logic (I know the Id of the order is unknow at this stage, because the primary key of order is auto-incremented (I use MySQL)).
I don't know how to make this work with one call to orderService (without saving orderLines with orderLinesRepository first). Is it even possible ?
Regards
An Order can contain many Books and a Book can appear in many Order(s). So the many-to-many relation is your OrderLine object essentially. I would set an id (autogenerated) and two many-to-one relations in OrderLine. Then you discard the OrderLinesPK class, you save the Order, Book and OrderLine objects in this order in the same transaction.In this way, your model is simpler and you only need to save an extra id (with no physical meaning) in the database (the id of the OrderLine object)