#OneToMany unidirectional with unique elements - jpa

I have two entities -
#Entity
class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
#Entity
class TaskGroup {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany
private List<Task> tasks=new ArrayList<>();
}
As you can see the relation is unidirectional. What I want is -
No join table
Task on a TaskList should be unique.
I want the mapped column to be created on TaskList table. Task table should not have any clue about the relation.
Can someone tell me how can achieve that?
I am using latest JPA with Hibernate.

I dont think that jpa can handle this without a join table.
Actually i think even if jpa could you should handle this behaviour in the objects.
You should override the equals and hashcode methods of Task and change the List to Set in the TaskGroup.
Or you can check the list in the TaskGroup's #PrePersist and #PreUpdate methods.

Related

Querying revisions of nested object using spring-data-envers

I'm trying to implement entity auditing in my Java Spring Boot project using spring-data-envers. All the entities are being created as they should, but I've come up against a brick wall when executing the query.
parentRepository.findRevisions(id).stream().map(Parent::getEntity).collect(Collectors.toList());
During this select the repository is supposed to fetch info also from the child entity, instead I get unable to find <child object> with {id}.
According to my experiments categoryId is being searched in the Category_Aud table, instead of the actual table with desired data.
Code snippets:
#Data
#Entity
#Audited
#NoArgsConstructor
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private Status status;
#Enumerated(EnumType.STRING)
private Type requestType;
private String fullName;
#ManyToOne
#JoinColumn(name = "child_id")
private Child child;
}
#Data
#Entity
#Audited
#NoArgsConstructor
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
}
I've extended Parent with RevisionRepository
#Repository
public interface ParentRepository extends RevisionRepository<Parent, Long, Long>, JpaRepository<Parent, Long>
And annotated my SpringBootApplication entry class with:
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
I couldn't find any explanation for this so far, how can make parentRepository get what I need?
The underlying problem here is that the reference from a versioned entity isn't really properly defined. Which variant of the reference should be returned? The one at the start of the version you use as a basis, the one at the end? The one that exists right now?
There are scenarios for which each variant makes sense.
Therefor you have to query the revisions yourself and can't simply navigate to them.

OneToMany and ManyToOne Relationship

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/

Can I use more than one #Id annotation in an Entity?

I want to define a table where the entire record is the primary key. The table has two columns which are references to other entities.
#Entity
public class ProtoList implements Serializable {
#Id
#ManyToOne ProtoObject listID;
#Id
#OneToOne ProtoObject po;
ProtoObject is an entity whose #Id is a regular generated Long.
The resulting relational data structure is intended allow any ProtoObject to be associated with an arbitrarily long List (actually a Set) of ProtoObjects. So the two table columns are just two Longs, always unique.
Will this work or do I have to define an #IdClass or something else?
After some experimentation I discovered that it was indeed necessary to use an #IdClass annotation. What is interesting is that in the Entity itself I have the #ManyToOne and #OneToOne annotations to create relational links to ProtoObjects, but in the IdClass the corresponding fields are inferred from the ProtoObject's own ID field.
So the result is:
#Entity
#IdClass(ProtoListKey.class)
public class ProtoList implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne ProtoObject listID;
#Id
#OneToOne ProtoObject po;
And the key is:
public class ProtoListKey {
private Long listID;
private Long po;
The primary key of ProtoList is Long so this works. The entire record is the primary key which is what I wanted. Lesson learned.

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.