JPA ManyToMany and mappedBY - jpa

I completely understand #OneToMany, #ManyToOne, and #ManyToMany. However the mappedBy = "some collection or class" has be confused.
From my understanding, the many part is always the owning side. For example,
#Entity
#Table(name = "company")
public class CompanyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idcompany")
private Integer idcompany;
#Basic(optional = false)
#Column(name = "name")
private String name;
#Basic(optional = false)
#Column(name = "address")
private String address;
#OneToMany
private Collection<EmployeeEnity> employeeEnity
This is saying a company can have many employees. The one being the company and the Many being the employees.
However with #ManyToMany we still have a inverse side too. This is what I do not understand. #ManyToMany just means there is a table in the middle, so how do you determine the inverse and the owner?
I know mappedBy is mandatory, but choosing on where to put it is confusing me.

For a bidirectional OneToMany, the many side MUST be the owner side.
For a ManyToMany, you have the choice: you decide which side is the owner side and which side is the inverse side.
Note that, in your example, either the association is unidirectional, and the unique side (the one side) is thus obviously the owner side, or the association is bidirectional, and the mapping is thus incorrect, since the one side MUST be the inverse side and should thus have a mappedBy attribute:
#OneToMany(mappedBy = "company")
private Collection<EmployeeEntity> employees;

Related

Why my foreign key is null when saving to h2 db, using JPA

What is the difference between these 2 codes. The 1st one shows null on my foreign key which is individualId. The 2nd one is not. Why?
//1st code:
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Individual {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INDIVIDUAL_ID")
private Long individualId;
#OneToMany(mappedBy="individual",cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Identification> identifications = new ArrayList<Identification>();
}
#Entity
public class Identification {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "IDT_ID")
private Long id;
#ManyToOne
#JoinColumn(name="individualId")
private Individual individual;
//second code
//replaced #OneToMany in the first code & then i just dont add #ManyToOne in the Identification Class and it works fine. Why?
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INDIVIDUAL_ID", referencedColumnName = "INDIVIDUAL_ID")
private List<Identification> identifications = new ArrayList<Identification>();
When i search for JPA tutorial in google the 1st code is the one that i always read. declare #OneToMany in the parent class and add mappedBy, declare #ManyToOne in the child class. But why the 2nd code works perfect than the 1st code? it just let me declare #OneToMany only in the parent class ?
In the class Identification the name of the #JoinColumn does not match any column in your class Individual. It must be the name of the column in the database, which is INDIVIDUAL_ID:
#JoinColumn(name="INDIVIDUAL_ID")

How to show 2 different type of mappings between 2 entity classes, holding each other's reference

The mappings between the 2 tables(Department and Employee) is as follows (Link for the image showing mapping is also provided):
Every department has one and only one department head.
Every department can have more than one employee.
dept_id and empId are primary keys of their respective tables.
dept_head(It is the Employee Id) and dept are foreign keys of their
respective tables.
Mapping Employee and Department table
I created entity classes for the above 2 tables (The structure is provided below).
Employee Class:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "empId")
private Integer empId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 45)
#Column(name = "address")
private String address;
#Size(max = 45)
#Column(name = "grade")
private String grade;
#Size(max = 45)
#Column(name = "email")
private String email;
#JoinColumn(name = "dept", referencedColumnName = "dept_id")
#ManyToOne
private Department deptartment;
.. ...
}
Department class:
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 8)
#Column(name = "dept_id")
private String deptId;
#Size(max = 45)
#Column(name = "name")
private String name;
#JoinColumn(name = "dept_head", referencedColumnName = "empId")
#OneToOne
private Employee deptHead;
#OneToMany(mappedBy = "deptartment")
private List<Employee> employeeList;
....
...
}
If I am adding mappedBy in Employee Class (like I did in Department), to show OneToOne mapping between empId and deptHead,the code is compiling and running. However, If I do not add the mappedBy statement in Employee class, as the above code shows, the code still compiles and runs fine.
I would want to know why the code above works even if I am not providing mappedBy in employee class.
If anybody can help me clearing the above doubts and explaining the logic behind its working would be great as I am new to this.
It is not quite clear where you tried to user it with and without the mappedBy attribute.
But if I get your question correctly, you ask why you can have only one or both sides annotated?
It depends on which side is the source and destination of your relation or wheter it's bi-directional. On the Java-side you can have a relation always in both directions due to object references, but on the Database-side, you might only have it in one direction.
Check out JPA Wiki book on that topic for more details.
Additionally, the API doc for OneToOne states:
Specifies a single-valued association to another entity that has
one-to-one multiplicity. It is not normally necessary to specify the
associated target entity explicitly since it can usually be inferred
from the type of the object being referenced. If the relationship is
bidirectional, the non-owning side must use the mappedBy element of
the OneToOne annotation to specify the relationship field or property
of the owning side.

Feed a list with the last value

I have theses entity and I do this query.
select r from RentAmount r Join r.lodger l join l.bailList b where r.unpaidBalance > 0 and (r.paymentDueDate > :date or r.paymentDueDate is null ) and b.paymentPeriod= order by r.rentAmountId")
Is there a way to feed Lodger.bailList only with the last bail or i would need to loop on every record to get this information?
#Entity
public class RentAmount {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long rentAmountId;
#OneToOne
private Lodger lodger;
}
#Entity
public class Lodger{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long lodgerId;
#OneToOne(fetch = FetchType.LAZY, mappedBy="lodger")
private RentAmount rentAmount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY, mappedBy = "lodger", orphanRemoval = true)
private List<Bail> bailList;
}
#Entity
public class Bail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long bailId;
#Enumerated(EnumType.STRING)
private PaymentPeriodEnum paymentPeriod;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
}
There are a few options:
One (Non JPA, Hibernate Only)
Ensure the collection is correctly ordered and mark it is as extra lazy. You will have access to the whole collection but accessing of individual items will not trigger a full load.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html
"Extra-lazy" collection fetching: individual elements of the
collection are accessed from the database as needed. Hibernate tries
not to fetch the whole collection into memory unless absolutely
needed. It is suitable for large collections.
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#LazyCollection(LazyCollectionOption.EXTRA)
#OrderBy("theRelevantProperty ASC")
private List<Bail> bailList;
public void getCurrentBail(){
//will only load this item from the database
return bailList.get(bailList.size() - 1);
}
Two (Non JPA, Hibernate Only.)
Use the #Where annotation to filter the collection so that while still #OneToMany, only one element will be accessible.
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-collection
The mapping will look like:
#OneToMany(mappedBy = "lodger")
#Where(clause="some native sql which will filter to include onyl 1item"))
private List<Bail> bailList;
public void getCurrentBail(){
//will be the only item accessible
return bailList.get(0);
}
Three (JPA Compliant)
Would involve creating views at the database level. Various options in this area. If we are only ever interested in the current bail then this view would be similar to option 2 above. Simply point the Bail entity to this view rather than the concrete table:
#Entity
#Table(name = "vw_active_bail")
public class Bail {
}

JPA -- Using the one-to-one dependency relationship on insertion

I have 2 entity classes with one-to-one dependencies on their primary keys:
The primary table:
#Entity
#Table(name = "tablePrimary")
#XmlRootElement
//...
public class TablePrimary implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "code")
private String code;
// set the dependency of table2 to this class
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Table2 table2inst;
// ...
} // end of class TablePrimary
The dependent table:
#Entity
#Table(name = "table2")
#XmlRootElement
//...
public class Table2 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#MapsId
#OneToOne(mappedBy = "table2inst")
#JoinColumn(name = "id")
private TablePrimary tablePrimaryInst;
//...
} // end of class Table2
Whenever there is a row with say, id==55 in TablePrimary, there is
a row with the same id==55 in Table2 and vice-versa.
So in essence, these two tables are one table in logical level-- split into 2 physical tables for practicality.
When i'm inserting a row into the "logical" table,
i first am inserting to TablePrimary-- the primary table in the relationship,
getting the value of id==55 field of this new row i just inserted and inserting a row to
Table2 with that id value.
As part of this, i'm checking, just in case,
whether a row with id==55 is already in Table2.
Is there a better way of doing this?
Does JPA have a feature to make these two insertions to these two physical tables
by using the 1-1 dependency I configured on them-- without me having to do it "manually" in the code? Or a control feature on the id fields of the tables I set the dependency on?
If there is-- how is done? how does it handle the key value collision in the dependent table-- Table2?
A similar thing will come up on deletion. However, i'm not there yet, and might figure out out of this.
TIA.
You can take advantage of JPA cascading. You will have to define a cascade on the owning side (the one with the join column). If you have set the owning side of the relationship and persist the owning side, the inverse side will be persisted as well:
TablePrimary tp = new TablePrimary();
Table2 t2 = new Table2();
t2.setTablePrimaryInst(tp);
entityManager.persist(t2);
The 'mappedBy' element is supposed to be placed on the inverse side. You entities could look like this:
public class Table2 ...
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "tp_id")
private TablePrimary tablePrimary;
public class TablePrimary...
#OneToOne(mappedBy="tablePrimary")
private Table2 table2;

JPA Many to One relationship

I am bit beginner on JPA and need some help on fetching the Many to One relationship in JPA.
I have below entities.
User which stores all user information . User extends Audiatable abstract class which is for holding auidt paramters like last modified date, creation date etc.
I am trying to add another fields as lastUpdatedByUser which should get fetched from lastUpdatedBy for which I amtrying to add Many-One relationship.
But the relation is not working somehow, am I doing something wrong here?
AuditableEntity.java
public abstract class AuditableEntity<T extends Entity<T, ID>, ID> implements Auditable {
private static final long serialVersionUID = 1L;
#Column(name = "cruserid")
private Long createdBy;
#Column(name = "crdate")
#Type(type = JpaConstants.TYPE_LOCAL_DATE_TIME)
private LocalDateTime createdOn;
#Column(name = "chuserid")
private Long lastUpdatedBy;
#Column(name = "chdate")
#Type(type = JpaConstants.TYPE_LOCAL_DATE_TIME)
private LocalDateTime lastUpdatedOn;
#Transient
#ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
#JoinColumn(name = "usrId", referencedColumnName = "chuserid")
private User lastUpdatedByUser;
User.java
public class User extends AuditableEntity<User, Long> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "usrId")
private Long id;
#Column(name = "usrName")
private String name;
#Column(name = "loginame")
private String loginName;
}
Well, you marked the association with #Transient, which means that the field is not persistent and should be ignored by JPA.
And you also seem to have two different fields to store the same information: lastUpdatedBy and lastUpdateByUser. Remove the first one, and map the second one as
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "chuserid")
private User lastUpdatedByUser;
This tells that the association is a ManyToOne to the User entity (no need to specify the targetEntity since it's the type of the field), and that this association is materialized by the join column named "chuserid", in the auditable entity's table, and referencing the ID of the User entity (referencedColumnName is only useful when you use composite IDs, or when you reference an entity by a column which is the the ID)