I had two POJO class named Task and Team.A team can have many tasks correspondingly but each task can be mapped only one team.
// Task POJO
#Entity
#Table(name = "Task")
public class Task extends Domain implements Serializable {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long taskId;
//Mapping To Team
#ManyToOne
#JoinColumn(name="teamId")
private Team teamId;
Team POJO
#Entity
#Table(name = "Team")
public class Team extends Domain implements Serializable {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long teamId;
#Column(nullable = false)
#OneToMany(mappedBy="teamId")
private List<Task> task = new ArrayList<Task>();
The issue is I couldn't Map/Save/Update and which is not affecting my Team Pojo.
//Task Table
+-----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+----------------+
| taskId | bigint(20) | NO | PRI | NULL | auto_increment |
| taskName | varchar(255) | NO | | NULL | |
| teamId | bigint(20) | YES | MUL | NULL | |
+-----------------+--------------+------+-----+---------+----------------+
The Team Table
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| teamId | bigint(20) | NO | PRI | NULL | auto_increment |
| teamName | varchar(255) | NO | | NULL | |
+----------+--------------+------+-----+---------+----------------+
So How do I map these two Pojo classes and affect when saving/deletion of data in the tables.
Thanks in Advance.
I discovered that you have defined #Column at the one to many association property (tasks), I assume it was a type error.
For bi-directional one to many association, updates one side of the relationship, the other side should also get updated, and be in sync. Below shown how the make both entity in sync:
#Entity
#Table(name = "Task")
public class Task extends Domain implements Serializable {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long taskId;
//Mapping To Team
#ManyToOne
#JoinColumn(name="teamId")
private Team team;
public void setTeam(Team team) {
this.team = team;
if (!team.getTasks().contains(this)) {
team.getTasks().add(this);
}
}
}
#Entity
#Table(name = "Team")
public class Team extends Domain implements Serializable {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long teamId;
#Column(nullable = false)
#OneToMany(mappedBy="team")
private List<Task> tasks = new ArrayList<Task>();
public void addTask(Task task) {
this.tasks.add(task);
if (task.getTeam() != this) {
task.setTeam(this);
}
}
}
#OneToMany(mappedBy="teamId", cascade=CascadeType.ALL), try to add this annotation above the member(attribute) task of the class Team
Complete your #manyToOne mapping in the Task entity by adding the referenced column in the Team entity; and also name the member as 'team', not 'teamId' i.e.:
#ManyToOne
#JoinColumn(name="teamId",
referencedColumnName="teamId")
private Team team;
To understand relationship mapping in JPA in general, see this: https://en.wikibooks.org/wiki/Java_Persistence/Relationships#Nested_Collections.2C_Maps_and_Matrices
Related
I have a many to many relation in my class but the problem is that the table created by spring boot contains and id which is not a primary key.
My code looks like:
#JoinTable(name = "T_Commande_Produit",
joinColumns = #JoinColumn(name = "idCommande"),
inverseJoinColumns = #JoinColumn(name = "idProduit"))
private List<Produit> products;
And the table created looks like this
+-------------+--------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------+------+-----+---------+-------+
| id | bigint | NO | MUL | NULL | |
| id_commande | bigint | NO | MUL | NULL | |
| id_produit | bigint | NO | MUL | NULL | |
+-------------+--------+------+-----+---------+-------+
If you are creating ManyToMany relation then you don't need a third ID variable you can simply set the primary key as id_commande and id_produit combination and you don't need a third entity in this case.But if you still want to manually create a table that includes three fields that is the id, id_commande, and id_produit then you can create an Entity class That contains OneToMany Relation with others.
Code Example :
The third Entity is a table referencing both the Produit and Commande.
#Entity
class ThirdEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(name = "id_commande")
private Commande commande;
#ManyToOne
#JoinColumn(name = "id_produit")
private Produit produit;
}
Produit Entity
#Entity
class ProduitEntity {
// constructors and other fields excluded for simplicity.
#OneToMany(mappedBy = "produit") // here produit is a object name of Produit in ThirdEntity
private List<ThirdEntity> list;
}
Commande Entity
#Entity
class CommandeEntity {
// constructors and other fields excluded for simplicity
#OneToMany(mappedBy = "commande") // here commande is a object name of Produit in ThirdEntity
private List<ThirdEntity> list;
}
I've got two tables in my database that look like this, with a foreign key from job_label.job_id to equivalent column in job_record. Additionally, the triple of job_id, label_key, and label in job_record has a unique constraint.
mysql> select * from job_record;
+--------+---------+
| job_id | state |
+--------+---------+
| 1 | success |
| 2 | running |
| 3 | errored |
| 4 | success |
+--------+---------+
mysql> select * from job_label
+--------+-----------+--------+
| job_id | label_key | label |
+--------+-----------+--------+
| 1 | name | job 1 |
| 1 | type | normal |
+--------+-----------+--------+
On the Java class side I have this class:
#Entity
#Table(name = "job_record")
public class JobRecord {
#Id
#Column(name = "job_id")
private String jobId;
#Enumerated(EnumType.STRING)
#Column(name = "state")
private JobState state;
}
I've tried to define a class for job_label that looks something like this:
public class JobLabelRecord {
#Enumerated(EnumType.STRING)
#Column(name = "label_key")
private JobLabelKey key;
#Column(name = "label")
private String label;
}
And then I want a field in JobRecord that provides me all labels for that Job as a List<JobLabelRecord>. However, nothing I've tried works.
I've tried declaring JobLabelRecord as Embeddable with the equivalent field in JobRecord as Embedded. I've tried using ManyToOne and OneToMany mappings, but that fails because there's no Id columns in JobLabelRecord (and nothing I do with those works correctly).
Am I supposed to be using an ElementCollection here instead? I've tried that as well, but without success.
Any ideas here? Thanks!
You can find a simple example for this by searching for "jpa elementcollection separate table", such as JPA Tutorial - JPA ElementCollection CollectionTable Override Example. Applying this example to your problem gives the following:
#Entity
#Table(name = "job_record")
public class JobRecord {
#Id
#Column(name = "job_id")
private Integer jobId;
#Enumerated(EnumType.STRING)
#Column(name = "state")
private JobState state;
#ElementCollection
#CollectionTable(name="job_label",
joinColumns=#JoinColumn(name="job_id"))
private List<JobLabelRecord> labels;
...
#Embeddable
public class JobLabelRecord {
#Enumerated(EnumType.STRING)
#Column(name = "label_key")
private JobLabelKey key;
#Column(name = "label")
private String label;
...
Note also the JobRecord id should probably be an Integer.
I was using Hibernate 4.2 and app was works fine.
After update to 4.3 I'm getting the hibernate error org.hibernate.MappingException: Unable to find column with logical name: cd_banco in TB_AGENCIA.
#Table(name = "TB_AGENCIA")
public class Agencia {
private Banco banco;
private String codigoAgencia;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cd_banco", referencedColumnName = "cd_banco")
public Banco getBanco(){
return banco;
}
#Id
#Column(name = "cd_agencia")
public String getCodigoAgencia(){
return codigoAgencia;
}
}
The database structure is:
|-------------------|
| TB_AGENCIA |
|-------------------|
| cd_banco PK, FK |
| cd_agencia PK |
| ... |
|-------------------|
|-------------------|
| TB_BANCO |
|-------------------|
| cd_banco PK |
| ... |
|-------------------|
I added a bidirectional relationship in the Banco class, but didn't work
public class Banco{
private String codigo;
private List<Agencia> agencias;
#Id
#Column(name = "cd_banco")
public String getCodigo(){
return codigo;
}
#OneToMany(mappedBy="banco")
public List<Agencia> getAgencias() {
return agencias;
}
}
Hibernate UnUniqueify a column in table(Solved)
I want a field set to be non-unique on itself but to be unique in combination with the other field, I got this table with two columns(composite primary keys); id (primary key) and object_proxy_id (primary key), this is exactly what I need but hibernate sets the object_proxy_id to be unique on itself so that value cant be duplicate in the table, and I need this column to accept duplicate values. Because every user has its own object proxy and these proxy's don't have to be necessarily unique.
This is what I want to achieve:
|-------------------------------|
| tbl_object_proxy |
| ------------------------------|
| Id (pk)| object_proxy_id (pk) |
|-------------------------------|
| 1 | 150 -- |
| 1 | 149 |= must be able to be DUPLICATE which is not the case right now.
| 2 | 150 -- |
| 2 | 151 |
|-------------------------------|
Current code:
#Entity
#Table(name = "tbl_user_settings", uniqueConstraints = {#UniqueConstraint(columnNames={"user_id"})})
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Settings implements Serializable
{
#Id
#SequenceGenerator(name="someSequence", sequenceName="SEQ_SOMENAME", allocationSize =1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="someSequence")
#Column(name="id")
private int setting_id;
#OneToOne
private User user;
#ManyToOne
private SomeObject someobject;
#ElementCollection
#CollectionTable(name="tbl_collection_name", joinColumns=
#JoinColumn(name="id"), uniqueConstraints = {#UniqueConstraint(columnNames={"id", "object_proxy_id"})})
#Column(name="SomeObject")
private Set<SomeObject> objectProxy;
/*...constructors and methods...*/
}
Results in:
-- Table schema
|-------------------|
| tbl_user_settings |
|-------------------|
| id |PK <<Unique>>
| user_id |FK reference tbl_user <<Unique>>
| object_id |FK reference tbl_object
|-------------------|
|------------------|
| tbl_object_proxy |
|------------------|
| id |PK reference tbl_user_settings
| object_proxy_id |PK reference tbl_object <<Unique>> BUT I DON'T WANT THIS TO BE UNIQUE ON ITSELF !!!!
|------------------|
EDIT:
The two primary key's in tbl_object_proxy are composite primary key's
I have tried Xeon's solution but it didn't work.
Short answer: replace the #ElementCollection by a #ManyToMany relation with a #JoinTable like this:
#ManyToMany
#JoinTable(
name="tbl_settings_objecteproxy_v2",
joinColumns = #JoinColumn(name = "id"),
inverseJoinColumns = #JoinColumn( name = "objectproxy_id"))
private Set<SomeObject> objectproxy;
See "2.2.5.3.2.1. Definition" in Hibernate Annotation Documentation
This results in a same side table but then without the unique constraint.
So now this is possible:
|-------------------------------|
| tbl_object_proxy |
| ------------------------------|
| Id (pk)| object_proxy_id (pk) |
|-------------------------------|
| 1 | 150 -- |
| 1 | 149 |= It works! The unique constraint is gone!
| 2 | 150 -- |
| 2 | 151 |
|-------------------------------|
Detailed answer and cause description:
Somehow the #ElementCollection created a collectiontable with a one to many relation of the referenced key (collection | inverse join) which adds a unique constraint to the key referencing the other side table to reflect the one to many relationship which I didn't want. So I dropped the #ElementCollection and replaced it by a #ManyToMany relation with a #JoinTable annotation. I have also tried to declare the #ManyToMany relation in the #ElementCollection but it kept adding the Unique constraint to the referenced key.
My Settings class does now look like this:
#Entity
#Table(name = "tbl_user_settings", uniqueConstraints = {#UniqueConstraint(columnNames={"user_id"})})
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Settings
{
#Id
#SequenceGenerator(name="someSequence", sequenceName="SEQ_SOMENAME", allocationSize =1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="someSequence")
#Column(name="id")
private int setting_id;
#OneToOne
private User user;
#ManyToOne
private SomeObject someobject;
#ManyToMany
#JoinTable(
name="tbl_settings_objecteproxy_v2",
joinColumns = #JoinColumn(name = "id"),
inverseJoinColumns = #JoinColumn( name = "objectproxy_id"))
private Set<SomeObject> objectProxy;
/*...the rest...*/
}
I had similar issue with articles and categories:
public class ArticleCategoriesEntity {
#EmbeddedId
public ArticleCategoriesIdPk getArticleCategoriesIdPk() {
return articleCategoriesIdPk;
}
public void setArticleCategoriesIdPk(ArticleCategoriesIdPk articleCategoriesIdPk) {
this.articleCategoriesIdPk = articleCategoriesIdPk;
}
...
#Embeddable
public class ArticleCategoriesIdPk implements Serializable {
public ArticleCategoriesIdPk() {
}
public ArticleCategoriesIdPk(Integer articleCategoryIdPk, Integer articleCategoryVersionFk) {
this.articleCategoryIdPk = articleCategoryIdPk;
this.articleCategoryVersionFk = articleCategoryVersionFk;
}
private Integer articleCategoryIdPk;
#Column(name = "article_category_id_pk")
public Integer getArticleCategoryIdPk() {
return articleCategoryIdPk;
}
public void setArticleCategoryIdPk(Integer articleCategoryIdPk) {
this.articleCategoryIdPk = articleCategoryIdPk;
}
private Integer articleCategoryVersionFk;
#Column(name = "article_cat_version_fk")
public Integer getArticleCategoryVersionFk() {
return articleCategoryVersionFk;
}
public void setArticleCategoryVersionFk(Integer articleCategoryVersionFk) {
this.articleCategoryVersionFk = articleCategoryVersionFk;
}
And you need to set Uniqueness of the two columns of embedded PK class
I'm new to JPA 2.0 and have troubles annotating a n:m relationship that uses a foreign key class with additional attributes describing the relationship:
Customers can subscribe to several magazines, every Subscription is created for exactly one Customer and one Magazine, additionally saving the duration of the subscription.
Here are my annotated classes, I'm using field access. I've omitted some boilerplate code like constructors, setters, getters (not annotated) and the methods toString, equals and hashCode.
#Entity
public class Customer {
#Id
#GeneratedValue
private Long id;
private String name;
#ManyToMany
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Magazine {
#Id
#GeneratedValue
private Long id;
private String name;
#ManyToMany
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Subscription {
private Date start;
private Date end;
#EmbeddedId
private SubscriptionId id;
// ..
}
#Embeddable
public class SubscriptionId implements Serializable {
#ManyToOne
private Customer customer;
#ManyToOne
private Magazine magazine;
// ..
}
I test my annotations by creating and persisting a few objects, like this:
public static void main(String[] args) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("kiosk");
EntityManager em = emf.createEntityManager();
persist(em);
em.close();
emf.close();
}
private static void persist(EntityManager em) {
em.getTransaction().begin();
Magazine mag1 = new Magazine("mag1");
Magazine mag2 = new Magazine("mag2");
Customer cus1 = new Customer("cus1");
Customer cus2 = new Customer("cus2");
Customer cus3 = new Customer("cus3");
Subscription sub1 = new Subscription(cus1, mag1);
Subscription sub2 = new Subscription(cus2, mag1);
Subscription sub3 = new Subscription(cus2, mag2);
Subscription sub4 = new Subscription(cus3, mag2);
em.persist(mag1);
em.persist(mag2);
em.persist(cus1);
em.persist(cus2);
em.persist(cus3);
em.persist(sub1);
em.persist(sub2);
em.persist(sub3);
em.persist(sub4);
em.getTransaction().commit();
}
The provider creates the following MySQL database:
mysql> show tables;
+-----------------------+
| Tables_in_kiosk |
+-----------------------+
| customer |
| customer_subscription |
| magazine |
| magazine_subscription |
| subscription |
+-----------------------+
Only the three tables customer, magazine and subscription have contents:
mysql> select * from customer;
+-------------+------+
| customer_id | name |
+-------------+------+
| 1 | cus1 |
| 2 | cus2 |
| 3 | cus3 |
+-------------+------+
mysql> select * from magazine;
+-------------+------+
| magazine_id | name |
+-------------+------+
| 1 | mag1 |
| 2 | mag2 |
+-------------+------+
mysql> select * from subscription;
+------+-------+-------------+-------------+
| end | start | magazine_id | customer_id |
+------+-------+-------------+-------------+
| NULL | NULL | 1 | 1 |
| NULL | NULL | 1 | 2 |
| NULL | NULL | 2 | 2 |
| NULL | NULL | 2 | 3 |
+------+-------+-------------+-------------+
I can read my subscriptions if I know their keys. I haven't yet tried to read the whole set for a customer or magazine though.
private static void find(EntityManager em) {
Magazine mag1 = em.find(Magazine.class, 1L);
Magazine mag2 = em.find(Magazine.class, 2L);
Customer cus1 = em.find(Customer.class, 1L);
Customer cus2 = em.find(Customer.class, 2L);
Customer cus3 = em.find(Customer.class, 3L);
Subscription sub1 = em.find(Subscription.class, new SubscriptionId(cus1, mag1));
Subscription sub2 = em.find(Subscription.class, new SubscriptionId(cus2, mag1));
Subscription sub3 = em.find(Subscription.class, new SubscriptionId(cus2, mag2));
Subscription sub4 = em.find(Subscription.class, new SubscriptionId(cus3, mag2));
System.out.println(mag1);
System.out.println(mag2);
System.out.println(cus1);
System.out.println(cus2);
System.out.println(cus3);
System.out.println(sub1);
System.out.println(sub2);
System.out.println(sub3);
System.out.println(sub4);
}
Prints:
Magazine [id=1, name=mag1, subscriptions=null]
Magazine [id=2, name=mag2, subscriptions=null]
Customer [id=1, name=cus1, subscriptions=null]
Customer [id=2, name=cus2, subscriptions=null]
Customer [id=3, name=cus3, subscriptions=null]
Subscription [start=null, end=null, id=SubscriptionId [customer=1, magazine=1]]
Subscription [start=null, end=null, id=SubscriptionId [customer=2, magazine=1]]
Subscription [start=null, end=null, id=SubscriptionId [customer=2, magazine=2]]
Subscription [start=null, end=null, id=SubscriptionId [customer=3, magazine=2]]
The two tables customer_subscription and magazine_subscription remain empty. But as I see it they wouldn't even be necessary - the other 3 tables look exactly like I'd want them to. So my question is:
How do I correctly model the m:n relationship used in this example with JPA 2.0 without creating excess tables while retaining the ability to write and read all subscriptions for a magazine or customer?
In case someone is interested in the code, I've uploaded it here: http://goo.gl/qSc2e; you'll need a MySQL 5 database called 'kiosk' running at port 3306 on localhost with an empty root password.
Your model doesn't actually have any many-to-many relationships.
Customer to Subscription is one-to-many.
Magazine to Subscription is one-to-many.
Try this as your entity model:
#Entity
public class Customer {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Magazine {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Subscription {
private Date start;
private Date end;
#EmbeddedId
private SubscriptionId id;
// ..
}
#Embeddable
public class SubscriptionId implements Serializable {
#ManyToOne
private Customer customer;
#ManyToOne
private Magazine magazine;
// ..
}
and Hibernate won't generate the redundant link tables.
milkplusvellocetless's answer is part of the solution, adding mappedBy attributes to the #OneToMany annotations solves the problem:
#Entity
public class Magazine {
#Id
#GeneratedValue
private Long id;
#NotNull
private String name;
#OneToMany(mappedBy = "id.magazine")
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Customer {
#Id
#GeneratedValue
private Long id;
#NotNull
private String name;
#OneToMany(mappedBy = "id.customer")
private Set<Subscription> subscriptions;
// ..
}
#Entity
public class Subscription {
private Date start;
private Date end;
#EmbeddedId
private SubscriptionId id;
// ..
}
#Embeddable
public class SubscriptionId implements Serializable {
#ManyToOne
private Customer customer;
#ManyToOne
private Magazine magazine;
// ..
}
Creates only 3 tables (as wanted) instead of 5.