can't find the pattern of setting cascade logic - java

I have 3 tables which are Person Login and Account.
Person and Login is OneToOne relation and Login has one FK which is connected Person's id column called PERSON_ID.
Person(one) and Account(many) is OneToMany relation and Account has one FK which is connected Person's id column called PERSON_ID as well .
what i want to do is when i delete one data from Account , nothing happen to Person and Login.
if i delete one data from Person which id=1, Login's PERSON_ID=1 data will be deleted , and all of the data PERSON_ID=1 from Account will be deleted as well.
if i delete one data from Login which PERSON_ID=1, Person 's id=1 data will be deleted , and all of the data PERSON_ID=1 from Account will be deleted as well.
how should i set the cascade ?
i've tried dozens of times and still can't find the logic in there, thanks!!
here's my code of all 3 tables without setting cascade:
`
#Entity
#Table(name = "PERSON")
public class Person {
#Id
#Column(name = "ID", nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "NAME")
private String name;
#Column(name = "SEX")
private String sex;
#OneToMany(mappedBy = "person",fetch = FetchType.LAZY)
private List<Account> account;
#OneToOne(mappedBy = "person")
private Login login;
#get..
#set..
}
`
#Entity
#Table(name = "ACCOUNT")
public class Account {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "ACCOUNT")
private String account;
#Column(name = "AMOUNT")
private String amount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSON_ID",referencedColumnName = "ID")
public Person person;
#get..
#set..
}
`
#Entity
#Table(name = "LOGIN")
public class Login {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private long id;
#Column(name = "USERNAME")
private String userName;
#Column(name = "PASSWORD")
private String password;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSON_ID", referencedColumnName = "ID")
private Person person;
#get..
#set..
}

It's been a while, but if I'm not mistaken you need to use the cascade=REMOVE option on the OneToMany and OneToOne relationships. In the OneToOne I think you need to specify cascade=REMOVE on the side that does NOT own the relationship, that is, the side that also contains the "mappedBy" property.
Finally, I believe JPA will NOT automatically load lazy relationships and then cascade them. I'm thinking you may need to fetch the relationship before you delete the parent entity (otherwise JPA will not know what to delete).

Related

Springboot JPA Hibernate CascadeType confusion

How to make a column cascade enable only for insertion not update and delete.
Here are two class. There are #ManyToOne relationship between Qualification and Department. At the time of insertion I want to insert new department with qualification. But at the time of update of qualification I don't want to update department. How can I configure that??
#Table(name = "department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
#Table(name = "qualification")
public class Qualification implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
private Integer passingYear;
private String result;
#ManyToOne(optional = true, cascade = { CascadeType. ? }, fetch = FetchType.EAGER)
#JoinColumn(name = "department_id", referencedColumnName = "id")
private Department department;
}
CascadeType.PERSIST is what you are looking for. The various CascadeType enums essentially say, which persistence operation of EntityManager persist/merge/remove etc. should cascade to the objects of an association.

I wanted to create User and Role Entity class but the #Column annotation asks for a data source?

For the #Column names I am getting, assign data source from IntelliJ, I have set up the h2 as my platform and database url. I don't know how to setup this database source.
This is the User Entity class,
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private boolean enabled;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "users_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
and this is the Role entity class,
#Entity
#Table(name = "roles")
public class Role {
#Id
#Column(name = "role_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
// GETTERS AND SETTERS
}
You can configure database connections in IntelliJ as described here.
That said you only need to do that if you want IntelliJ to check if table and column names, queries, etc. you put in your code are correct. Not setting datasource in IntelliJ will not affect your application in any way.

Is there a way to map child entity to parent entity using parent entity field (not parent object)?

I'm trying to model one to many unidirectional association. I have two entities the first one (parent) is:
#Entity
#Table(name = "customer")
public class Customer{
#Id
#Column(name = "ID")
private Long id;
The second entity has many to one relation to Customer:
#Entity
#Table(name = "address")
public class Address{
#Id
#Column(name = "ID")
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "ID")
private Customer customer;
I need to substitute property Customer in Address class by customer.id, is it possible?
You can use customerId field in Adress entity and join it manually with JPQL but it's not recommended and not creates foreign key.
#Entity
#Table(name = "address")
public class Address{
#Id
#Column(name = "ID")
private Long id;
#Column(name = "CUSTOMER_ID")
private Long customerId;

I have to persist a Map<EntityType, List<EntityType>> with JPA

I'm trying to persist an Entity that has a Map as one of its values. To be more precise. I have the #Entity Request that have a compound primary key with three elements. This primary key is composed by an id, the User an Map<EntityType, List<EntityType>> where the first EntityType is the selected service and the related value is the list of the items where the service will be applied to.
Below the code that I have but I'm missing the annotation that i have to use for the Map. I read online that the good way to go is the create a wrapper entity like to one that i created (SelectedService2MyItem) that holds the list and then the map is just a key-value pair between two entity but I can't make it works and I don't know how to proceed.
Does anyone can help me?
Request Entity
#Entity
public class Request {
#EmbeddedId
private RequestId id;
#Column
private String name;
#ManyToOne
#JoinColumn(name = "user_id", foreignKey = #ForeignKey(name = "FK_user_id"), nullable=false)
private User user;
//Getter, setter, constructor omitted
}
RequestId
#Embeddable
public class RequestId {
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "user_id", foreignKey = #ForeignKey(name = "FK_user_id"), nullable=false)
private User user;
private Map<ServiceOffered, SelectedService2MyItem> service2MyItem = new HashMap<ServiceOffered, SelectedService2MyItem>();
//Getter, setter, constructor omitted
}
SelectedService2MyItem
#Entity
public class SelectedService2MyItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#OneToMany(mappedBy = "id")
private List<MyItem> myItemsSelected;
//Getter, setter, constructor omitted
}

What hibernate / jpa annotation is required

I am trying to create a new User(entity1) - it has reference to a Group (entity2) via a link table Member (entity3)
A user has a Set of groups as a class variable.
When i create my user object i want to say this user will be a member of group n (there are pre defined users that are linked to by id (1,2,3,4,5,6...) each group has some associated data in the table.
Whenever I create my user object as follows;
User user = new User();
user.setActive(1);
user.setCrby("me");
user.setUsername("username");
user.setCrdate("2016-06-20 12:42:53.610");
user.setCrwsref("...");
user.setModby("...");
user.setModdate("2016-06-20 12:42:53.610");
user.setModswref("..");
user.setBackground("Y");
user.setPassword("password");
user.setFullName("me");
Group group = new Group();
group.setId(1);
Group group2 = new Group();
group2.setId(2);
Set<Group> sets = new HashSet<Group>();
sets.add(group);
sets.add(group2);
user.setGroups(sets);
userDao.addUser(user);
I keep getting errors telling me that certain columns cannot be null. What I actually want to happen here is not to be doing an insert in to the group table but associating a user to a line in the group table. Is there a particular way I can prevent the columns in the group table being modified? I think I need to modify the mappings between the link table - this is how much pojos link right now
User
#Entity
#Table(name = "user")
public class User
{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "zmember", joinColumns = {#JoinColumn(name = "username")}, inverseJoinColumns = {#JoinColumn(name = "id")})
private Set<Group> groups = new HashSet<Group>(0);
Member link table
#Entity
#Table(name = "member")
public class Member implements Serializable
{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Id
#Column(name = "sgpid")
private int sgpid;
#Column(name = "username")
private String memberUsername;
Group
#Entity
#Table(name = "group")
public class Group
{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
What is happening is there is no association to the link Member table so ideally should User have a set of member objects rather than a set of groups?
Thanks - this was quite hard to explain so sorry if it is hard to understand
This is a typical case for the #ManyToMany annotation. See for example:
https://dzone.com/tutorials/java/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html
The relationship from User to Group is essentially ManyToMany. You could model this is using the #ManyToMany annotation however one drawback with this approach is you cannot save additional information about the group in the join table such as 'date_joined'.
See: https://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#ManyToMany
Using this approach you would not need the Join entity Member and the relationship on User would look like:
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "zmember", joinColumns = {#JoinColumn(name = "member_id", referencedColumnName = "id")}, inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")})
private Set<Group> groups = new HashSet<Group>(0);
The alternative to using #ManyToMany is to use a Join entity Member(ship) as you have done. This would allow you to save additional data about the relationship (by defining additional field mappings in the Join entity).
In this case the mappings would look like:
User:
public class User{
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Membership> memberships = new HashSet<Membership>(0);
//if required, you can 'hide' the join entity from client code by
//encapsulating add remove operations etc.
public void addToGroup(Group group){
Membership membershup = new Membership();
membership.setUser(this);
membership.setGroup(group);
memberships.add(membership);
)
public Set<Groupp> getGroups(){
//iterate memberships and build collection of groups
}
}
Membership:
public class Membership{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#ManyToOne
#JoinColumn(name = "user_id")
private Member member;
#ManyToOne
#JoinColumn(name = "group_id")
private Group group;
}
Group:
#Entity
#Table(name = "group")
public class Group
{
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#OneToMany(mappedBy = "group", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Membership> memberships = new HashSet<Membership>(0);
}

Categories