Joining three tables with #OneToMany association - spring-data-jpa

I have three tables.
1.Street (street_id, settlement_entity_id, street_name),
2.Settlement_entity (settlement_entity_id, settlement_id, settlement_name), for example could be community, regional, municipality.. and
3.Settlement (settlement_id, settlement_name), for example could be city, town, township, village....
Relation - Street - Settlement_entity = > onetomany
Relation - Settlement_entity - Settlement = > onetomany
I want when I enter the name of the street, I get the settlement entity as above
as in parentheses and after that the settlement name with characteristics that are not to be the subject of this application, such as for example the house/apartment number, floor, longitude, latitude, altitude of the settlement.
entity
Street.java
package net.javaguides.springboot.entity;
#Entity
#Table(name = "street")
public class Street {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long street_id;
#Column(name = "street_name")
private String street_name;
public Street(String street_name) {
super();
this.street_name = street_name;
}
// getter and setters
entity
Settlement_entity.java
package net.javaguides.springboot.entity;
import javax.persistence.Column;
#Entity
#Table(name = "settlement_entity")
public class SettlementEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long settlement_entity_id;
#Column(name = "settlement_entity_name")
private String settlement_entity_name;
public SettlementEntity(String settlement_entity_name) {
super();
this.settlement_entity_name = settlement_entity_name;
}
// getters and setters
public void setSettlement_entity_name(String settlement_entity_name) {
this.settlement_entity_name = settlement_entity_name;
}
}
entity
Settlement.java
package net.javaguides.springboot.entity;
import javax.persistence.Column;
#Entity
#Table(name = "settlement")
public class Settlement {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long settlement_id;
#Column(name = "settlement_name")
private String settlement_name;
public Settlement(String settlement_name) {
super();
this.settlement_name = settlement_name;
}
// getters and setters
}
I creating according suggestion from -thelearner new linking entity which would be used for mapping that particular table.
entity linking table
StreetSettlementEntitySettlement.java
package net.javaguides.springboot.entity;
import javax.persistence.CascadeType;
public class StreetSettlementEntitySettlement {
#Id
#GeneratedValue
private long id;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "street_id")
private Street street;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "settlement_entity_id")
private SettlementEntity settlement_entity;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "settlement")
private Settlement settlement;
public StreetSettlementEntitySettlement(long id, Street street, SettlementEntity
settlement_entity, Settlement settlement) {
super();
this.id = id;
this.street = street;
this.settlement_entity = settlement_entity;
this.settlement = settlement;
}
}
Directory structure
I saw some proposal from thelearner like this:
It's not clear for me and don't understanding. Where should I put those three classes or should do something else. Repo's is clear.
Any help and explanation would be appreciated. Thank you

Related

JPA dataIntegrityViolationException occurs for multiple parents

I am working on simple spring security demo and want to put user and role info into db. Here is the simple structure of my entity.
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#OneToMany(mappedBy = "users", fetch = FetchType.LAZY, orphanRemoval=true, cascade = CascadeType.ALL)
private List<UserRoleMapping> userRoleMapping;
}
//
#Entity
#Table(name = "user_role_mapping")
public class UserRoleMapping {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_role_mapping_id")
private Long userRoleMappingId;
#ManyToOne(fetch = FetchType.LAZY)
private Users users;
#ManyToOne(fetch = FetchType.LAZY)
private UserRole userRole;
}
//
#Entity
#Table(name = "users_role")
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private Long roleId;
#Column(name = "role")
private String role;
#Column(name = "role_desc")
private String roleDesc;
#OneToMany(mappedBy = "userRole", fetch = FetchType.LAZY, orphanRemoval=true)
private List<UserRoleMapping> userRoleMapping;
}
In my use case, I have to make sure when the user is created then I have to insert subsequence userRoleMapping. And If the userRole is removed then the userRoleMapping must be deleted as well.
So I put CascadeType.ALL and orphanRemoval=true in users entity, and orphanRemoval=true in userRole entity.
However, when I run userRoleRepository.delete(userRole). I have dataIntegrityViolationException.
I did some researches on it and understand it is a kind of jpa constrains to make sure we delete the parents (users) as well.
May I ask if there are any workaround for my use case?
Thanks
Here is the solution to my use cases. Instead of using OneToMany in both entity, I should use ManyToMany relationship. And it is quite make sense as I don't care (for now) the mapping in java logic. Here is my code
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
#JoinTable
private Set<UserRole> userRole;
}
//
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private Long roleId;
#Column(name = "role")
private String role;
#Column(name = "role_desc")
private String roleDesc;
#OneToMany(mappedBy = "userRole", fetch = FetchType.LAZY)
private Set<Users> users;
}

Hibernate - Spring Data JPA One To Many unique constraint across table

I have a department and employee table. I need the dept name and employees in the department to be unique such that a new entry for the dept with the same set of employees is given it should throw a unique constraint violation error.
I am not sure how to work this out in hibernate.
I need to have unique constraints across multiple tables.
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(
name="dept"
)
public class DeptEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#OneToMany(mappedBy = "dep", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> attributes = new ArrayList<>();
}
import javax.persistence.*;
#Entity
#Table(name="emp"
)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
#JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
private DeptEntity dep;
}
You can use like :
#Column(unique= true)
private String name;

JPA two Entities one Relationship: How do I obtain a Set of an entity that is linked through a relationship?

I have three tables each mapping to one of these entities. The 'assigned' table acts as the relationship between 'users' and 'roles' with a foreign key to each table. How would I map this on my entities so that I can get a Set of EntityRoles from the UserEntity? I can't quite figure out how to make this work. Is this even possible?
#Entity
#Table(name = "users")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="user_id")
private long id;
#Column(name="user_username")
private String username;
#Column(name="user_password")
private String password;
#Column(name="user_email")
private String email;
//I want to be able to get a set of RoleEntities
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id")
private Set<RoleEntity> roles;
}
#Entity
#Table(name = "assigned")
public class AssignedEntity implements Serializable {
#Id
//#Column(name = "assigned_role")
#ManyToOne(targetEntity = RoleEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_role")
private long roleId;
#Id
//#Column(name = "assigned_user")
#ManyToOne(targetEntity = UserEntity.class, fetch = FetchType.LAZY)
#JoinColumn(name = "fk_user")
private long userId;
}
#Entity
#Table(name = "roles")
public class RoleEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
#OneToOne(fetch = FetchType.LAZY, mappedBy="roleId")
private long id;
#Column(name="role_name")
private String name;
}
You are using an incorrect/inconvenient mapping. Always keep things as simply as possible.
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
}
#Entity
#Table(name = "roles")
public class Role {
#Id
private Long id;
#Column
private String name;
}
A persistent provider will create a (valid) join table for you. You can specify the name of the join table using #JoinTable annotation. Also you will need to think about auto generation values of id for the Role entity: the roles table is something like a reference data table. So, probably, you will need to hardcode the id values.
To get user roles (in the persistent context):
user.getRoles()

Spring data : issue with OneToOne relationship

I am developping a webapp (Spring J2EE/angularjs)
I want to set a relationship between two entities :
citizen (id, lastName, city)
city (id, cityName)
A citizen live in only one city.
I need to find a city from a citizen.
I don't need to find a citizen from a city.
I have done that :
#Entity
#Table(name = "citizen")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Citizen implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "last_name")
private String lastName;
#OneToOne
private City city;
}
#Entity
#Table(name = "city")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class City implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "city_name")
private String cityName;
}
In database I have inserted data. Citizen 1, 2 and 3 are linked to City 1
and Citizen 4 is linked to City 2
When I try to load all citizen, I am getting the error:
More than one row with the given identifier was found: 1, for class: com.myApp.rh.domain.Citizen
What's wrong in my entities?
Thanks
It seems that you are missing the #JoinColumn annotation in your Citizen entity.
#Entity
#Table(name = "citizen")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Citizen implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "last_name")
private String lastName;
#OneToOne
#JoinColumn(name = "id", unique = true)
private City city;
}
#Entity
#Table(name = "city")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class City implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "city_name")
private String cityName;
}

JPA OneToOne not working

I followed by tutorial : http://www.codejava.net/frameworks/hibernate/hibernate-one-to-one-mapping-with-foreign-key-annotations-example
I have following code:
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User{
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
private UserActivationCode userActivationCode;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
public UserActivationCode getUserActivationCode() {
return userActivationCode;
}
}
#Entity
#Table(name = DomainConstant.TABLE_USER_ACTIVATON_LINK)
public class UserActivationCode {
#Id
#Column(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
#GeneratedValue
private Long userActivationCodeId;
#Column(name = DomainConstant.DOMAIN_ACTIVATION_DATE)
#Temporal(javax.persistence.TemporalType.DATE)
private Date date;
#Column(name = DomainConstant.DOMAIN_ACTIVATION_CODE)
private String code;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
}
When I save the User object it does not make record in UserActivationCode, why?
Like this:
User newUser = new User();
newUser.setUserActivationCode(new UserActivationCode("this is example"));
userDao.save(newUser);
I have record only in user table.
Can you tell me why?
Your problem is that you are mixing access types. In the User entity you have specified #Id on a field (private Long userId) whereas you have defined the join mapping on a property (the getter to UserActivationCode). If you specify the join mapping on the field, it should work as is.
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User{
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
private UserActivationCode userActivationCode;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
public UserActivationCode getUserActivationCode() {
return userActivationCode;
}
}
For more information on access and access types, see Access, Java EE 7