Link between entities with JPA - java

I'm creating a java web application, and for the backend, I use JPA and a h2 database.
I have for the moment one class called Secteur and one class called Bassin.
In my conception, one Secteur can have many Bassin, but one Bassin can have just one Secteur. Moreover it's not possible to create a Bassin if there is no Secteur already created (because one Bassin is already linked to a Secteur).
This is the Secteur class :
#Entity
public class Secteur {
#Id
#GeneratedValue
private int id;
private String nom;
...
}
And this is the Bassin class :
#Entity
public class Bassin {
#Id
#GeneratedValue
private int id;
private String nomBassin;
private int tailleMax;
private int tailleUtilise;
private Date dernierNetoyage;
private String etatBassin;
private int idSecteur;
...
}
After a lot of research, I had seen that different annotation exist like #ManyToOne, #OneToMany, etc. But I don't know how to use them in order to resolve my problem.
1) Can you help me please ?
2)Moreover if I use these annotations can I remove "private int idSecteur" ?
Thank you in advance for your help !

The Secteur entity mapping should be:
#Entity
public class Secteur {
#Id
#GeneratedValue
private int id;
private String nom;
#ManyToOne
#JoinColumn(name="secteur_id", nullable=false)
private Bassin bassin;
}
The bassin entity mapping should be:
#Entity
public class Bassin {
#Id
#GeneratedValue
private int id;
private String nomBassin;
private int tailleMax;
private int tailleUtilise;
private Date dernierNetoyage;
private String etatBassin;
#OneToMany(mappedBy="bassin")
    private Set<Secteur> secteurs;
}
Note that secteur_id in the annotation refers to the name of secteur id column in database.
I advise you to take a look to this more complete reference

Related

Can Hibernate map subset of columns into an internal sub Pojo

I have the following Pojo:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
private long lastVisited;
private long lastPlayed;
private long lastPayed;
...
}
I would like somehow if possible to map the Pojo like this:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
#Embedded
private UserStatistics statistics;
...
}
#Embeddable
class UserStatistics {
private long lastVisited;
private long lastPlayed;
private long lastPayed;
}
BUT, I DON'T want to move the statistics columns into a new
USER_STATISTICS table and do #OneToOne mapping.
Is there a Hibernate trick I can use here?
Thanks!
What you did is already enough, Hibernate does not require you to define fields for all columns in your table. It's rather the other way around - all non-transient fields should be reflected as columns in the corresponding table either using name defined in #Column annotation or generated using a naming convention used in hibernate configuration.
The example you presented is sufficient and will work, but I wouldn't recommend it as you can have two entities mapping single row at the same time.

#OneToMany does not create the join table

I'm new to JPA. Suppose I have these two entities:
//Imports
#Entity
#Table(name="article", schema = "sch_client")
public class Article implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
private int amount;
//Getters & setters
}
And
#Entity
#Table(name="purchase", schema = "sch_client")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
private List<Article> listArticle;}
I want to have something like a purchase contains many articles.
My question is: is it possible with only #OneToMany in Purchase class that points to Article class to have the desired relationship (a purchase contains many articles). Or to use a #OneToMany annotation I have to add a #ManyToOne on Article class. If so, why is is mandatory to add the #ManyToOne? any explanation please.
Thanks in advance.
First of all, I have write a misleading title, I will change it to make it more accurate:
Old title : In JPA, is it possible to use #OneToMany without using #ManyToOne?
New title : #OneToMany does not create the join table.
As I said, I'm new to JPA, my problem can appear dumb, I could delete the question, but I decided to keep it in case someone someday will face similar situation, it can help!
The join table of Purchase and Article was created every time I executed the code very normally, but I didn't notice!, I was checking the logs of NetBeans
and didn't see the join table, I was misled by those logs, I think that a join table doesn't appear in the logs (I hope that someone can confirm this information and make an edit of this answer).
I have created Purchase and Article in a new schema named: sch_sales. and the join table was created in public schema (PostgreSQL).
So, to make it more correct I added schema to #JoinTable as shown below, like this I will have all my tables in the same schema.
#Entity
#Table(name="purchase", schema = "sch_sales")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
#JoinTable(name="join_purchase_article", schema = "sch_sales", joinColumns = #JoinColumn(name="sales_fk"), inverseJoinColumns = #JoinColumn(name="article_fk"))
private List<Article> listArticle;
}
UPDATE :
I was having a 3rd table created containing the id of Purchase and Article (a join table) which is obviously not correct.
The normal "behavior" is to have an id_purchase column added in Article, in this page I have find how to have such a result.
To have the desired result, I used the code below:
#Entity
#Table(name="purchase", schema = "sch_sales")
public class Purchase implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany
#JoinColumn(name="id_purchase")
private List<Article> listArticle;
}

JPA #MapsId vs #JoinColumn(updatable=false, insertable=false)

It seems to me that there is virtually no difference between the below two ways of mapping. Here is an example base on #MapsId javadoc:
// parent entity has simple primary key
#Entity
public class Employee {
#Id long empId;
...
}
// dependent entity uses EmbeddedId for composite key
#Embeddable
public class DependentId {
String name;
long empid; // corresponds to primary key type of Employee
}
#Entity
public class Dependent {
#EmbeddedId DependentId id;
...
#MapsId("empid") // maps the empid attribute of embedded id
#ManyToOne Employee emp;
}
What if I change Dependent's mapping to:
#Entity
public class Dependent {
#EmbeddedId DependentId id;
#ManyToOne
#JoinColumn("empid", insertable=false, updatable=false)
Employee emp;
}
What is the difference of the above two approach?
So, I tested #MapsId for my usage when in the table I have only one foregin key it was no different. But for tables where I have two foregin keys to one table like ...
UserTable, and EmailTable-> #MapsId(owner)UserTable owner, #MapsId(receiver) UserTable receiver i have problems with that. Hibernate throws exceptions. So i have to back to old #JoinColumn way of doing that. That was a one differemce that I met with that adnotations.
I am using combination of both #MapsId and #JoinColumn together to avoid getting extra field getting created in DB for associating the entities. IF I ignore #JoinColumn, an extra field is getting created in DB.
#Entity
public class BookingsModel implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private SlotDateModel slotDateModelObj;
#JsonProperty
String slotnumber;
#MapsId("memberid")
#JsonBackReference
#ManyToOne
#JoinColumn(name="memberid",referencedColumnName = "memberid")
#NotNull
MemberModel memberModel;
.
.
.
}
#Entity
public class MemberModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#JsonProperty
#Id
String memberid;
#JsonProperty
String name;
#JsonIgnore
String phoneno;
#JsonManagedReference
#OneToMany
Set<BookingsModel> bookings;
.
.
.
}
#Embeddable
public class SlotDateModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
String memberid;
String slotdate;
.
.
.
}
Tables generated with #JoinColumn
Table generated when #JoinColumn is commented Can notice that the extra field "member_model_memberid" is getting added.

JPA - Using composite PK's and FK's and defining relationships

I got these 2 entities:
#javax.persistence.Entity
public class Book {
#javax.persistence.EmbeddedId
private BookPK id;
private String title;
#javax.persistence.ManyToOne(fetch = javax.persistence.FetchType.LAZY)
#javax.persistence.JoinColumns({
#javax.persistence.JoinColumn(name = "LNGCOD", referencedColumnName = "LNGCOD"),
#javax.persistence.JoinColumn(name = "LIBCOD", referencedColumnName = "LIBCOD") })
private Language language;
}
#javax.persistence.Entity
public class Language {
#javax.persistence.EmbeddedId
private LanguagePK id;
private String name;
}
with composed PK's:
#Embeddable
public class BookPK implements Serializable {
private Integer bookcod;
private Integer libcod;
}
#Embeddable
public class LanguagePK implements Serializable {
private Integer lngcod;
private Integer libcod;
}
If I try to create a new Book and persist it, I get an exception telling me libcod is found twice in the insert statement ("Column 'libcod' specified twice"). But I can't use "insertable = false" when defining the JoinColumn ("Mixing insertable and non insertable columns in a property is not allowed").
Is there any way to define these objects + relationship so the columns are managed automatically by Hibernate ? (I am especially thinking of libcod).
Thank you.
Create a third property "Integer libcod;" on the Book. Have that property manage the db state of libcod. Use insertable=false,updatable=false for both properties in the join to Language. in your "setLanguage" set the private libcod = language.libcod. don't expose a getter/setter for the private libcod.
Are any of the values generated at insert time? This could complicate things further, I suppose.

JPA Mapping Error -not provided sufficient metadata in your id class

I am trying to do mapping in JPA.
#Entity
public class Auction {
#Id
private Integer auctionId;
#OneToMany(mappedBy="auctionId")
#MapKey(name="auctionParamId")
private Map<AuctionParam, AuctionParamValue> values;
}
#Entity
public class AuctionParam {
#Id
private Integer auctionParamId;
private String description;
}
#Entity
public class AuctionParamValue {
#EmbeddedId
private AuctionParamValuePK pk;
private String value;
}
#Embeddable
public class AuctionParamValuePK {
#ManyToOne
#JoinColumn(name="auctionId")
private Auction auction;
#ManyToOne
#JoinColumn(name="auctionParamId")
private AuctionParam auctionParam;
}
Showing an error:-
.Error-Details:-Exception Description:
Entity [class
com.eaportal.domain.AuctionParamValue]
uses [class
com.eaportal.domain.AuctionParamValuePK]
as embedded id class
whose access-type
has been determined as [FIELD].
But
[class
com.eaportal.domain.AuctionParamValuePK]
does not define any [FIELD]. It is
likely that you have not provided
sufficient metadata in your id class
[class
com.eaportal.domain.AuctionParamValuePK].
If you come up with a solution please let me know.
Thanks in Advance
Tushar
You cannot use an EmbeddedId with relationships. Use an IdClass.
#Entity
#IdClass(AuctionParamValuePK.class)
public class AuctionParamValue {
#Id
#ManyToOne
#JoinColumn(name="auctionId")
private Auction auction;
#Id
#ManyToOne
#JoinColumn(name="auctionParamId")
private AuctionParam auctionParam;
#Basic
private String value;
}
public class AuctionParamValuePK {
private int auction;
private int auctionParam;
}
I think there are some errors in your Auction class. This is how I think it should look
#Entity
public class Auction {
#Id
private Integer auctionId;
#OneToMany(mappedBy="auction") // not auctionId
#MapKey(name="auctionParam") // not auctionParamId
private Map<AuctionParam, AuctionParamValue> values;
}
(The annotation values have to correspond with fields (or properties), not with columns)

Categories

Resources