OneToOne relationship, keep only foreign key - java

I am trying to establish a OneToOne relationship between two entities (PartnerDetails and JWTData. How ever, I only want to store the primary key of PartnerDetails entity in JWTData, not the whole object, like this.
#Entity
#Data
#Table(name = "partner_details")
public class PartnerDetails {
#Id
#Column(name = "partner_id")
private String partnerId;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "partnerId")
private JWTData jwtData;
}
#Entity
#Data
#Table(name = "jwt_data")
#NoArgsConstructor
public class JWTData {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(targetEntity = PartnerDetails.class)
#JoinColumn(name = "partner_id", foreignKey = #ForeignKey(name = "fk_jwt_partnerdetails_partnerid"))
private String partnerId;
#NotBlank
private String secret;
}
But after fetching the JWTData using repository, Hibernate cannot convert the String to a PartnerDetails. Can this be done using any other way?

If you just add PartnerDetails to JWTData then JPA will know to use only the id. JPA is an Object Oriented framework so you should reference objects unless you specifically want a field. JPA handles the details for you. Note that in this configuration JWTData in the "owning" entity because of the mappedBy annotation, therefore only setting the partnerDetails field in a JWTData instance will persist the relationship to the database. The jwtData field in PartnerDetails is for query results only and makes for a Bidirectional instead of a Unidirectional mapping. Also, because of this, having a CascadeType setting generally only makes sense on the owning entity since it is the one handling the database updates and deletes.
When playing around with JPA be sure to turn on the SQL output so that you know what is actually happening.
#Entity
#Data
#Table(name = "partner_details")
public class PartnerDetails {
#Id
#Column(name = "partner_id")
private String partnerId;
#OneToOne(mappedBy = "partnerDetails")
private JWTData jwtData;
#Entity
#Data
#Table(name = "jwt_data")
#NoArgsConstructor
public class JWTData {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// even though it looks like the entire class it's only saving the id to the database.
#OneToOne
private PartnerDetails partnerDetails;

Related

JPA one to one mapping creates multiple query when child entity is not found

I have a parent entity 'contracts' that has a one-to-one relation with another entity 'child-contract'. the interesting thing is that the mapping field ('contract_number')id not a primary key-foreign key but is rather a unique field in both the tables. Also it is possible for a contracts to not have any child contract altogether. With this configuration I have observed hibernate to generate 1 additional query every time a contracts does not have a child-contract. I filed this behavior very strange. Is there a way to stop these unnecessary query generation or have I got something wrong.
below is a piece of my code configuration.
#Data
#Entity
#Table(name = "contracts")
public class Contracts implements Serializable {
#Id
#JsonIgnore
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
#OneToOne(fetch=FetchType.EAGER)
#Fetch(FetchMode.JOIN)
#JsonProperty("crm_contracts")
#JoinColumn(name = "contract_number", referencedColumnName = "contract_number")
private ChildContract childContract ;
}
#Data
#NoArgsConstructor
#Entity
#Table(name = "child_contract")
#BatchSize(size=1000)
public class ChildContract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty("id")
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
}
Please help.
Thank-you
You can use NamedEntityGraph to solve multiple query problem.
#NamedEntityGraph(name = "graph.Contracts.CRMContracts", attributeNodes = {
#NamedAttributeNode(value = "crmContract") })
Use this on your repository method as
#EntityGraph(value = "graph.Contracts.CRMContracts", type = EntityGraphType.FETCH)
// Your repo method in repository

ManyToOne realtionship in Java Spring Boot

Well, I have a class Feeding.java and a class User.java
One Feeding should have one User but a User can have many Feedings.
This is my Feeding.java class:
#Getter
#Setter
#EqualsAndHashCode
#NoArgsConstructor
#Entity
#Table(name = "tblFeeding")
public class Feeding {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idFeeding;
private LocalDateTime dateFeeding;
private double amountFeeding;
private String foodFeeding;
#ManyToOne
#JoinColumn(name = "id_user")
private User user;
}
This is my User.java class:
#Entity
#Getter
#Setter
#Table(name = "tbl_User")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer idUser;
private String nameUser;
private String email;
private String passwordUser;
The problem at the moment is that I can save feeding object with an userId that doesn't exist and this shouldn't be possible.
A foreign constraint is missing. If you have created the table with Hibernate ORM it shouldn't happen but if you've created the table in a different way, it's possible that the foreign constraint has not been created.
You would need to run a SQL query similar to this one:
ALTER TABLE Feeding
ADD CONSTRAINT id_user_fk
FOREIGN KEY (id_user) REFERENCES User;
Note that the query might be different, you need to check the exact query for your database.
This query is from the Hibernate ORM documentation example for many-to-one associations.

Mapping one to many relationship in separate table

I am trying to develop a system for managing dormitories. Since I don't have much experience with databases, I am stuck on a problem and I have a solution but I am not sure if this would be the right approach.
So I have Room and User. Each user can be accommodated in one room, but one room can accommodate more users. I would like to manage this relationship in one entity - Accommodation. Here I would have more properties, like start/end Date, etc.
I am using Hibernate to map the tables. From what I've read, persisting Collections from Java can be done in two ways, either by #OneToMany or by #ElementCollection. I am not quite sure if I should define this relationship in the Room entity or in the Accommodation entity? If I do it in the room entity then the Accommodation would hold just fk from the room/user tables?
Also, is it possible to only fetch the primary key when doing one-to-many relations instead of getting the whole object? I know that FETCH.LAZY does this, but in my Accommodation entity ideally I would want to store only Set studentsIds.
Thank you in advance.
#Table(name = "student")
#AllArgsConstructor
#Data
#Embeddable
#NoArgsConstructor
#javax.persistence.Entity
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "role")
private String role;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "room", nullable = false)
private Room room_number;
}
Here is the Room entity
#javax.persistence.Entity
#Table(name = "room")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Data
public class Room
{
#Id
#Column(name = "room_number")
private Long roomNumber;
#Column(name = "location_address")
private String locationAddress;
#Column(name = "dormitory_name")
private String dormitoryName;
}
Accommodation entity
#javax.persistence.Entity
#Table(name = "accommodation")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Data
public class Accommodation extends Entity {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "room_number")
private Room room_number;
#OneToMany(mappedBy = "room_number", // I am not sure about this
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true) private List<Student> students;
#Column(name = "date_from")
private Date dateFrom;
#Column(name = "date_to")
private Date dateTo;
}

How to manage OnetoOne inserting data in child only

I am very new to hibernate and I am working with JPA and Hibernate4. Trying to insert parent object in child as onetoone relationship.
I went through some tutorials but All the example in the web shows, inserting both parent and child tables.
I want to insert data in child table only.
I have two tables called user and department.
User table consists of user details with department as onetoone relationship, as follows,
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department departmentId;
// getters and setters...
}
Below is my Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
// getters and setters...
}
In department table there is only 4 data. I want to insert data only in user data while insert into it and don't want to insert in Department.
How can I do that.Please assist.
You have to use mappedBy for this, as mentoned below in child Table, Department in your case
#OneToOne(mappedBy="department")
private UserEntity user;
These posts explain you better this,
JPA JoinColumn vs mappedBy
Understanding mappedBy annotation in Hibernate
You need to specify the relationship owner using mappedBy property in the OneToOne mapping in the owner side, here in your case in the Department class, you should add:
#OneToOne(mappedBy="department")
private UserEntity user;
I updated your code, to included the stated annotation and also renamed the Department property in your UserEntity class from departmentId to department to avoid confusion between relationship owner and its id:
#Entity
#Table(name = "User")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentId")
private Department department;
// getters and setters...
}
Below is the Department entity,
#Entity
#Table(name = "Department")
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "_id")
private String id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy="department")
private UserEntity user;
// getters and setters...
}
This will give you the right mapping with the expected behaviour.
In the #OneToOne annotation, the default value for parameter optional is true. So your annotation is the same as #OneToOne(fetch = FetchType.EAGER, optional = true). This means you can simply leave the Department in a UserEntity instance empty. In that case, persisting it results in persisting only a user entity and no department.
Even if you created a Department instance and assigned it to a UserEntity instance, persisting the UserEntity would not automatically persist the Department, since you don't have any cascade parameter in your annotation. If you don't automatically cascade persists, you would have to persist the Department first and then persist the corresponding user entity.
Maybe you're asking about using existing departments for your user entities. In that case, you first need to get the department via Hibernate (or the JPA API) from an entity manager. The entity instance you get is managed by Hibernate, and you can then set it in a UserEntity and persist that, to have it refer to the department.
Finally, I think one department will probably have more than one user. It might make more sense to have a #ManyToOne annotation instead of #OneToOne, indicating multiple users can refer to the same department, but that depends on your domain model.

Hibernate delete orphan on replacing OneToOne relationship

I have the following entity:
#Entity
#Getter
#Setter
#ToString
public class Team extends EntityBase {
......
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
orphanRemoval = true, optional = false)
#JoinColumn(name = "auth_id")
private TeamAuthentication auth;
......
}
so it has a TeamAuthentication table reference. The latter entity looks as follows:
#Entity
#Getter
#Setter
#ToString
public class TeamAuthentication {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String accessToken;
}
What I want is that when I fetch existing Team entity from the table and replace a reference to TeamAuthentication table there for field auth, then persist this Team entity with teamRepository.save(), I want that old TeamAuthentication would be deleted from its table. At the moment it stays in the table and becomes sort of a loitering entry that won't be ever used or queried.
How can I leverage Hibernate cascade in deleting OneToOne reference on change?

Categories