#OneToMany side of the relation populates well but the #ManyToOne side overrides each time(only the last item persists)
#Entity
#Table(name="order")
public class Order {
#Id
#Column(name ="orderId")
private String orderId;
#OneToMany(targetEntity = Items.class,
fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "orderId")
#NotNull
private Set<Items> items;
.......
}
#Entity
public class Items {
#Id
private String itemId;
#ManyToOne
#JoinColumn(name="orderId",referencedColumnName = "orderId")
private Order order;
............
}
#Entity
#Table(name="order")
public class Order {
#Id
#Column(name ="orderId")
private String orderId;
#OneToMany(targetEntity = Items.class,
fetch = FetchType.EAGER, cascade = CascadeType.ALL
,mappedBy = "item_id")
#NotNull
private Set<Items> items;
.......
}
#Entity
public class Items {
#Id
private String itemId;
#ManyToOne
#JoinColumn(name="orderId",referencedColumnName = "orderId")
private Order order;
............
Replace targetEntity = Items.class by mappedBy = "order"
and remove referencedColumnName = "orderId" and #JoinColumn(name = "orderId") from OneToMany.
Also if you really need eager fetching delete it from OneToMany side - ManyToOne is eager by default.
Related
I want to build entity classes for the following relationship. I want an entity ProductWiseCustomer which has a composite key. Those key also mapped with Product and Customer entities. How to achieve the purpose?
So far what I have done.
Product.java
#Entity
#Table(name = "product")
public class Product {
#Id
private Long productId;
private String productName;
private Decimal productPrice;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CustomerProductCompound.class)
private Set<CustomerProductCompound> customerProductCompound;
//Constructor
//Setter-getter
}
Customer.java
#Entity
#Table(name = "customerinfo")
public class CustomerInfo {
#Id
private Long customerId;
private String customerName;
private Boolean isActive;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = CustomerProductCompound.class)
private Set<CustomerProductCompound> customerProductCompound;
//Constructor
//Setter-getter
}
CustomerProductCompound.java
#Embeddable
public class CustomerProductCompound
{
#ManyToOne
#JoinColumn(name = "customerId")
private CustomerInfo customerInfo;
#ManyToOne
#JoinColumn(name = "productId")
private Product product;
//Constructor
//Setter-getter
}
While running the application getting the following error:
Use of #OneToMany or #ManyToMany targeting an unmapped class: com.auth.model.CustomerInfo.customerProductCompound[com.auth.model.CustomerProductCompound].
One solution is to use a composite identifier with #EmbeddableId.
#Entity
public class ProductWiseCustomer {
#EmbeddedId
private ProductCustomerKey key;
}
#Embeddable
public class ProductCustomerKey {
#ManyToOne(fetch = FetchType.LAZY)
private Customer customer;
#ManyToOne(fetch = FetchType.LAZY)
private Product product;
}
Please see the hibernate documentation:
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite-aggregated
CustomerProductCompound as you have defined just the primary key of ProductWiseCustomer. Your collections inside CustomerInfo and Product must contain ProductWiseCustomer items, not its key.
#Entity
#Table(name = "product")
public class Product {
#Id
private Long productId;
private String productName;
private Decimal productPrice;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ProductWiseCustomer> productWiseCustomers;
}
#Entity
#Table(name = "customerinfo")
public class CustomerInfo {
#Id
private Long customerId;
private String customerName;
private Boolean isActive;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ProductWiseCustomer> productWiseCustomers;
}
Notice I added the mappedBy property in the annotations. It needs to point to the property name on the other side that refers to this object. The JPA name, not the SQL name. targetEntity is rarely necessary, and I've suggested orphanRemoval, so that if you remove one from the set, you don't have to manually delete it for it to go away.
As for the ProductWiseCustomer, you do need the same key as shown by Modular Coder
#Embeddable
public class ProductCustomerKey {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "customerId)
private Customer customer;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "productId")
private Product product;
}
But I recommend you use #IdClass instead of #EmbeddedId
#Entity
#IdClass(ProductCustomerKey.class)
public class ProductWiseCustomer {
#ManyToOne(fetch = FetchType.LAZY) // should be lazy here
#JoinColumn(name = "customerId)
private Customer customer;
#ManyToOne(fetch = FetchType.LAZY) // should be lazy here
#JoinColumn(name = "productId")
private Product product;
private OffsetDateTime createDate;
private String remarks;
// getters, setters
}
I am facing a hibernate problem in updainting the join table in one to many mapping with hibernate. Below are my two entity class and join table entity class.
ArticleCategoryMap.java
#Entity
#Table(name = "ARTICLECATEGORYMAP")
public class ArticleCategoryMap {
private static final long serialVersionUID = -5653708523600543988L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column ( name = "id")
Long id;
#ManyToOne(targetEntity = Article.class, fetch = FetchType.EAGER, optional = true, cascade = CascadeType.PERSIST)
#JoinColumn(name = "ARTICLE_ID", nullable = true, insertable = true, updatable = true)
private Article article;
#ManyToOne(targetEntity = Category.class, fetch = FetchType.EAGER, optional = true, cascade = CascadeType.PERSIST)
#JoinColumn(name = "CATEGORY_ID", nullable = true, insertable = true, updatable = true)
private Category category;
//setter and getter
}
Article.java
#Entity
#Table(name = "ARTICLE")
public class Article {
private long id;
private String title;
private String description;
private String keywords;
private String content;
#Id
#GeneratedValue
#Column(name = "ARTICLE_ID")
public long getId() {
return id;
}
//setter and getter
}
Category.java
#Entity
#Table(name = "CATEGORY")
public class Category {
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = #JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = #JoinColumn(name = "ARTICLE_ID")
)
#CollectionId(
columns = #Column(name="id"),
type=#Type(type="long"),
generator = "sequence"
)
private Collection<Article> articles;
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
public long getId() {
return id;
}
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = #JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = #JoinColumn(name = "ARTICLE_ID")
)
#CollectionId(
columns = #Column(name="id"),
type=#Type(type="long"),
generator = "sequence"
)
// setter an getter
}
Now suppose first time I have 2 elements in article table which is mapping to one entry of the category table. so the join table will look something like
Now due to some reason, I want to update the entry where the article entry will map to a new category ID. So the final DB should look like
So My problem Is how can I update this join table.
If you want one to many relationship (1 category have many articles and 1 article to 1 category) you dont need a join table.
The entity classes should look like that:
Category Entity:
Contains a Set of articles:
#Entity
#Table(name = "CATEGORY")
public class Category {
private long id;
private String name;
#OneToMany(mappedBy="category")
private Set<Article> articles;
......
}
Article Entity:
#Entity
#Table(name = "ARTICLE")
public class Article {
#ManyToOne
#JoinColumn(name="id", nullable=false)
private Category category;
private long id;
private String title;
private String description;
private String keywords;
private String content;
.......
}
For more details take a look at hibernate-one-to-many. Hope this helps.
Also move annotation from methods to fields. This:
private long id;
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
public long getId() {
return id;
}
Should be:
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
private long id;
public long getId() {
return id;
}
Many to many relationship:
At your database you have 3 tables:
CATEGORY
ARTICLE
ARTICLECATEGORYMAP (join table)
For many to many relationship entities would be:
Category Entity:
#Entity
#Table(name = "CATEGORY")
public class Category {
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
private long id;
private String name;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = { #JoinColumn(name = "CATEGORY_ID") },
inverseJoinColumns = { #JoinColumn(name = "ARTICLE_ID") }
)
Set<Article > articles = new HashSet<>();
.....
}
Article Entity:
#Entity
#Table(name = "ARTICLE")
public class Article {
#Id
#GeneratedValue
#Column(name = "ARTICLE_ID")
private long id;
private String title;
private String description;
private String keywords;
private String content;
#ManyToMany(mappedBy = "articles")
private Set<Category> categories = new HashSet<>();
.......
}
For more info take a look at many-to-many ralationship
I'm trying to use Spring Data to perform joined queries but one of my tables has a Composite Key and I'm not sure how to map the entities.
Here is an analogy of the data model:
table: device
pk=model_id
pk=serial_id
...
table: device_settings
pk=device_settings_id
fk=model_id
fk=serial_id
...
Here is an analogy of the code, which doesn't compile due to a "mappedby" attribute that is isn't present.
#Entity
#Table(name = "device_settings")
public class DeviceSettings {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "device_settings_id")
private Long id;
// Pretty sure this is the problem
#OneToMany(targetEntity = Device.class, mappedBy = "deviceKey", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "model_id", referencedColumnName = "model_id"),
#JoinColumn(name = "serial_id", referencedColumnName = "serial_id")})
private List<Device> devices;
}
#Entity
#Table(name = "device")
public class Device {
#Id
private DeviceKey deviceKey;
}
...
}
#Embeddable
public class DeviceKey implements Serializable {
private static final long serialVersionUID = -1943684511893963184L;
#Column(name = "model_id")
private Long modelId;
#Column(name = "serial_id")
private Short serialId;
}
Associations marked as mappedBy must not define database mappings like #JoinTable or #JoinColumn
To achieve your scenario you have to define #ManyToOne:
#ManyToOne(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "model_id", referencedColumnName = "model_id"),
#JoinColumn(name = "serial_id", referencedColumnName = "serial_id")})
private Device device;
This will end up model_id, serial_id, device_settings_id
or
Define #JoinColumn in Device Entity
Entities:
DeviceSettings :
#Entity
#Table(name = "device_settings")
public class DeviceSettings {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "device_settings_id")
private Long id;
#OneToMany( mappedBy = "deviceSettings", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
private List<Device> devices;
}
Device Entity :
#Entity
#Table(name = "device")
public class Device {
#EmbeddedId
private DeviceKey deviceKey;
#ManyToOne
#JoinColumn(name="device_settings_id")
private DeviceSettings deviceSettings;
//getters and setters
}
Note : you can decide which is the owner of the relationship and put your mappings accorindly either One Device has many device settings or other way around.
I have an entity called itineraryTraveller, and every itineraryTraveller can have many flightEntity. When I try to delete an itineraryTraveller (parent), from the database, I get this error message:
a foreign key constraint fails (`pquino01db`.`ITINERARYTRAVELLER_FLIGHTENTITY`, CONSTRAINT `FK_ITINERARYTRAVELLER_FLIGHTENTITY_flights_ID` FOREIGN KEY (`flights_ID`) REFERENCES `FLIGHTENTITY` (`ID`))"
Here is my itineraryTraveller entity:
#Entity
public class itineraryTraveller implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<flightEntity> flights;
#Temporal(javax.persistence.TemporalType.DATE)
private Date departureDate;
private String departureLocation;
private String arrivalLocation;
private double cost;
private char status;
private ArrayList<String> stops;
private String stopPrint;
private String userName;
private int iden;
// ...
}
And the flightEntity looks like this:
#Entity
public class flightEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Temporal(javax.persistence.TemporalType.DATE)
private Date departureDate;
private String airlineCode;
private String flightNumber;
private String departureLocation;
private String arrivalLocation;
private double businessCost;
private double economyCost;
private int numBusinessSeats;
private int numEconomySeats;
// ...
}
Can someone see the problem? I think my #OneToMany annotation might be missing something, but I'm not sure what. I want to delete both the parent and child at the same time.
Your relationship between the two entities is unidirectional as there is no mapping from flightEntity back to itineraryTraveller entity as you do not have a #JoinColumn on your flightEntity. There can be one of the following solutions for your problem:
Add a #ManyToOne annotation on the flightEntity as follows:
#Entity
public class flightEntity implements Serializable {
// ....
#ManyToOne
#JoinColumn(name="<name_of_foreignkey_column>")
private itineraryTraveller traveller;
// ...
}
And you have to add a mappedBy attribute to your #OneToMany annotation:
#OneToMany(mappedBy="traveller", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
Thereby making the relationship between the entities bidirectional.
This one can solve the problem if you already have tables in the database with a foreign key relationship.
Use #JoinTable annotation on the #OneToMany annotation:
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinTable(name="<join_table_name>", joinColumns=#JoinColumn("TRAVELLER_ID"), inverseJoinColumns=#JoinColumn("FLIGHT_ID"))
private List<flightEntity> flights;
(The names of the columns are considered to be examples, and can be changed.)
This last mapping is useful if you don't have tables in the database with foreign key column defined, and it will create a new table as an association between the tables; which is normally the case in a many-to-many relationships.
If it is possible use #ManyToOne annotation on the flights entity. This is normal way of mapping a one-to-many relationships.
Lastly, there are conventions in Java that state class names should begin with a capital letter. So I would rename the entity names to Flight and ItineraryTraveller.
Note that in some cases the #JoinColumn on the child object must have insertable = false and updatable = false like this:
#JoinColumn(name = "user_id", insertable = false, updatable = false)
public class User {
private List<UserRole> roles;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
public List<UserRole> getRoles() {
return this.roles;
}
public void setRoles(List<UserRole> roles) {
this.roles = roles;
}
}
public class UserRole {
#ManyToOne
#JoinColumn(name = "user_id", insertable = false, updatable = false)
private User user;
}
I have two class and I want to use OneToMany relation with EmbeddedId
(Im working with kundera framework)
my sensor entity class:
public class SensorEntitie implements Serializable {
#EmbeddedId
private CompoundKey key;
#Column
private float temperature;
#Column
private float pressure;
#OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinColumn(name="what I should to put here")
private List<PieceEntitie> pieces;
}
#Embeddable
public class CompoundKey
{
#Column
private String IdSensor;
#Column
private long date;
#Column(name = "event_time")
private long eventTime;
my piece class entity
public class PieceEntitie implements Serializable{
/**
*
*/
#Id
private String IdPiece;
#Column
private double width;
#Column
private double height;
#Column
private double depth;
but how can i fill the blank in #JoinColumn
I found the solution :
to use OneToMany relation with EmbeddedId, I should to declare JoinColumns and multiple of JoinColumn
#OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "idsensor", referencedColumnName = "idsensor"),
#JoinColumn(name = "date", referencedColumnName = "date"),
#JoinColumn(name = "event_time", referencedColumnName = "event_time")
})
You need to do some following steps for fixing problem
Remove #JoinColumn you dont need to write that statement
Remove #OneToMany to created object
Bind #OneToMany with getter method as per my following code
#OneToMany(mappedBy = "pieceEntitie", cascade = CascadeType.ALL,
fetch=FetchType.EAGER)
public Set<PieceEntitie> getPieceEntitie() {
return pieceEntitie;
}