OneToMany and ManyToOne Relationship - jpa

I have 2 tables mapped #OneToMany and #ManyToOne and their setters and getters, so a user can have multiple transactions and a transaction could have only one user.
If I add a transaction in the User's list data goes into the table correctly and transaction can be retrieved by using User's getter. But when I use getter from the Transaction to find its owner, it doesn't find its respectively user from users table.
Reverse is also available, if I set a user for a transaction data is persisted in database and user can be retrieved by using Transaction's getter, but use of User's getter doesn't show any transaction..
The only way is to add a transaction in the User's list and set user for the transaction. Why is this happening? I thought that if I use only one of this actions the reverse should be available automatically.
User
#Entity
#Table(name = "users")
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToMany(mappedBy = "user")
private Collection<Transaction> transactions;
Transaction
#Entity
#Table(name="user_transactions")
public class Transaction{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
I can't see any difference in tables, any action I do both tables have the same structure. How does JPA know how I saved the objects and build them back again...?

As far as I remember there is no default CascadeType.
You must specify one, for example in your case:
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Collection<Transaction> transactions;
you can read about cascade types here :
http://howtodoinjava.com/hibernate/hibernate-jpa-cascade-types/

Related

JPA Annotations - How to retrieve all entities with a specific column value

Let say I have an entity object Customer with an "OneToMany" relation to Order. I want that when ever a "Customer" get loaded, only his orders with the Id = 1234, 5678 get loaded to.
Any ideas?
#Entity
#Table(name = "Customer")
public class Customer extends TraceableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "customer_id")
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "Customer", targetEntity = Order.class)
#Column(name = "order_id", value = {"1234","5678"} (?))
#OrderBy("isrtdate ASC")
#BatchSize(size = 20)
private List<Order> orders = new ArrayList<Order>();
Hibernate
If you use hibernate Session and its abilites , you can always use #FilterJoinTable mechanism.
Check THIS article for more information.
Yet it is not global, you have to predefine this filter and then explicitly configure Session object to use it.
JPA
JPA in its standard has NO SUCH FUNCTIONALITY, for global relations filtering.
You can always filter it in your queries : )

ERROR: update or delete on table "tablename" violates foreign key constraint

I'm trying to delete the parent student or parent course and I get this error:
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "student" violates foreign key constraint "fkeyvuofq5vwdylcf78jar3mxol" on table "registration"
RegistrationId class is a composite key used in Registration class. I'm using Spring data jpa and spring boot.
What am I doing wrong? I know that putting cascadetype.all should also remove the children when the parent is deleted but it is giving me an error instead.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Registration class
#Entity(name = "Registration")
#Table(name = "registration")
public class Registration {
#EmbeddedId
private RegistrationId id;
When you're using a relational DB, you are setting entities with relationships between these entities.
The error that you're getting means that:
You're trying to delete a record that its primary key is functioning as a foreign key in another table, thus you can't delete it.
In order to delete that record, first, delete the record with the foreign key, and then delete the original that you wanted to delete.
I made it work by using hibernate #OnDelete annotation. Some how the JPA.persistence CascadeTypes were not working. They had no effect for whichever I chose.
Just like below. Now I can remove the parent Student or the parent Course and all children(Registrations) are deleted with them.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Foreign keys guarantee that an entry will exist in another table. This is a way of ensuring data integrity. SQL will never allow you to delete this entry while it still deletes in the other table. Either (1) this is letting you know you would have made a grave mistake by deleting this thing which is required or (2) you would like to put in a cascading delete so that not only is this entry deleted but so is what is supposed to be referencing it in the other table. Information on cascading deletes can be found here and written fairly easily (https://www.techonthenet.com/sql_server/foreign_keys/foreign_delete.php). If neither of these two descriptions fits you, evaluate why your foreign key relationship exists in the first place because it probably should not.
Try this method too. I got the answer with this method,This is just a test to remove.
Pay attention to the cascade!
MyUser Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private String mobile;
#Column(unique = true)
private String email;
private Long date;
private LocalTime localiime;
private LocalTime localiimeend;
#ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "role_fk"))
private Role role;
Role Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#OneToMany(mappedBy = "role", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<MyUser> users;
#ManyToOne (fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "rolecat_fk"))
private rolecat rolecat;
rolecat Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "rolecat", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Role> roles;

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 {
}

Unidirectional JPA

I have a database (JPA 2 Eclipselink) where there is Order and Item, each order can have many items and each item can be assigned only to one order. This is unidirectional relation.
The Order Entity:
#Entity
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
The Item entity has:
#Entity
public class Item implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
Order o;
}
But how to setup that if an order is deleted from the database all Items having reference to it would be deleted? Is it possible in unidirectional relationship, or I have to create bidirectional and put #OneToMany(cascade=remove) in the Order Entity Class? or keep it unidirectional but the owning side would be Order and remove any reference to order from item Entity?
Either you make the association bidirectional and add a cascade, as you suggest yourself in your question, or you explicitely delete all the items linked to the order (using a JPQL delete query, or by searching them and then deleting them), and then delete the order.
A bidirectional association makes sense in this case, and you'll probably benefit from it in several other places in your code.

JPA Relationship Mapping Concept

I have several questions on bidirectional mapping.
I have these entities:
Employee(1) - (1) Parking_Lot
Employee(*) - (1) Department
Employee(*) - (1) Project
What is the source and target entity for the above relationship?
What is the owner for ManyToOne relationship. I wonder the owner is
on Many entity or One entity?
Do mappedBy specify on owner side or inverse side?
Please help.
EDIT:
I have the following table:
Project - Proj_Client - Client (Many to Many relationship) and persist the project table but the client is not get persist. What wrong with it?
Thanks.
#Entity
#Table(name="empoyee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne
#JoinColumn(name="department_id", referencedColumnName="id")
private Department department;
#ManyToOne
#JoinColumn(name="project_id", referencedColumnName="id")
private Project projects;
#OneToOne(mappedBy="employee")
private ParkingLot parkingLot;
//Other properties,constructors, getters and setters and so on
}
#Entity
#Table(name="department")
public class Department implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="department")
private List<Employee> employees;
//Other properties,constructors, getters and setters and so on}
#Entity
#Table(name="parking_lot")
public class ParkingLot implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne
#JoinColumn(name="employee_id",referencedColumnName="id")
private Employee employee;
//Other properties,constructors, getters and setters and so on}
#Entity
#Table(name="project")
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="project")
private List<Employee> employees;
//Other properties,constructors, getters and setters and so on
}
If the relationship is unidirectional there really isn't an owning side, and there isn't any mappedBy annotations.
If the relationship is bidirectional there is a side with the mappedBy annotation - the other side is the owning side.
The owning side is the side that owns the relationship. So the term is not ment to be applied like a ParkingLot owns its Employee or an Employee owns its ParkingLot, but rather like the relationship between ParkingLot and Employee is owned by the Employee (or ParkingLot see below).
For ManyToOne there is no mappedBy, so it is always the entity specified under the OneToMany annotation that owns the relationship (makes sense, since the for example the project table can't have foreign keys to all its employees)
So for the two ManyToOne/OneToMany mappings in your example we don't have a choice in which side owns the relationship. Between Employee and ParkingLot we have a choice, I choosed ParkingLot.
When given a choice, what does it matter? Well, the main difference is that the mappedBy have the porperty cascade. Please note that it doesn't matter which table have the foreign key, or if the relationship is in its own table - JPA supports all cases (#InverseJoinColumn etc).
For bidirectional mappings there isn't a clear target and source for the mapping, it depends on which way you at the mapping from. The term is more applicable to unidirectional mappings, and there the source side is of course the entity with the mapping (that is possible knowledge of the target entity)
4) Not applicable (unless you make the relationship between ParkingLot and Employee unidirectional).
5) The owner of the relationship is always "on the One entity"
6) inverse side
Final note:
"owning side" is confusing, for example we could design so that a Department owns its Employees and if we delete a Department all its employees would also be deleted. This would be done by changing #OneToMany(mappedBy="department") into #OneToMany(mappedBy="department", cascade= CascadeType.REMOVE) then it would really make sense to say "the Department entity owns its Employee entities" but the relationship would still be owned by the Employee entity.