Child is not being inserted - java

I'm facing difficulties with saving objects with jpa repositories. I have two entities. One to one related:
#Entity(name="USER")
public class User {
#Id
#GeneratedValue
#Column(name = "USER_ID")
private Long userId;
private String username;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
#LazyCollection(LazyCollectionOption.FALSE)
private Wallet wallet;
and the Wallet
#Entity(name = "WALLET")
public class Wallet implements Serializable {
#Id
#GeneratedValue
#Column(name = "WALLET_ID")
private Long id;
#OneToMany(mappedBy = "wallet")
#Cascade({org.hibernate.annotations.CascadeType.ALL})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Paper> papers;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private User user;
I have the issue with this situation - hibernate is not saving the wallet when I'm adding new user:
public String addUser(#PathVariable("userName") String userName) {
UserDto userDto = new UserDto();
userDto.setUsername(userName);
WalletDto walletDto = new WalletDto();
userDto.setWalletDto(walletDto);
userService.addUser(userDto);
return userDto.toString();
}
and the addUser:
#Override
#Transactional
public void addUser(UserDto userDto) {
userRepository.save(userConverter.convertToEntity(userDto));
}
where save is jpa method.
EDIT:
public void addUser(UserDto userDto) {
User user = userConverter.convertToEntity(userDto);
Wallet wallet = walletConverter.convertToEntity(userDto.getWallet());
user.setWallet(wallet);
userRepository.save(user);
}
and really strange thing:
12:30:06,619 DEBUG EntityPrinter:121 - com.private.model.Wallet{id=6, papers=null, user=com.private.model.User#7}
12:30:06,619 DEBUG EntityPrinter:121 - com.private.model.User{username=xyzasew, userId=7, wallet=com.private.model.Wallet#6}
and in Wallet table there is no user trail = )
Edit. Almost there I hope = ):
I want wallet to be the master of user and paper, accordingly to Your advices I've eddited a bit entities:
#Entity(name = "WALLET")
public class Wallet implements Serializable {
#Id
#GeneratedValue
#Column(name = "WALLET_ID")
private Long id;
#OneToMany(mappedBy = "wallet", cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
private List<Paper> papers;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "wallet")
private User user;
and user:
#Entity(name="USER")
public class User {
#Id
#GeneratedValue
#Column(name = "USER_ID")
private Long userId;
private String username;
#OneToOne(cascade = CascadeType.ALL)
private Wallet wallet;
however wallet still does not have the user_id, and the user got it!

mappedBy basically means i am not the owner for the relationship, key is on the other side. Putting mappedBy on both side means nobody is the owner of the relationship.
Theoretically
Using "mappedBy" attribute of mapping annotations(like #OneToOne, #OneToMany, #ManyToMany) for bi-directional relationship. This attribute allows you to refer the associated entities from both sides. If "X" has association with "Y" then you can get X from Y and Y from X.
MappedBy signals hibernate that the key for the relationship is on the other side.
The annotation #JoinColumn indicates that this entity is the owner of the relationship. That is, the corresponding table has a column with a foreign key to the referenced table, whereas the attribute mappedBy indicates that the entity in this side is the inverse of the relationship, and the owner resides in the "other" entity.
Practically
#Entity
public class X implements Serializable {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="y_fk")
public Y getY() {
...
}
#Entity
public class Y implements Serializable {
#OneToOne(mappedBy = "y")
public X getX() {
...
}
Since this is annotated with mappedBy it shows that this is NOT the owner, and that the Owner is X (the field that is annotated). name attribute is telling Hibernate where to find the information about the FK mapping (inside X there is a getY() method). No additional fields will be created in Y.
Improvements to be done in the above code
#LazyCollection:
defines the lazyness option on #ManyToMany and #OneToMany
associations. LazyCollectionOption can be TRUE (the collection is lazy
and will be loaded when its state is accessed)
User.Java Entity changes can be reduced to below
#OneToOne(cascade = CascadeType.ALL)
private Wallet wallet;

Related

The DELETE statement conflicted with the REFERENCE constraint in dbo.interests

I am running into a problem deleting related entities from my database. I have a trading application where users can post trades and express their interests in other people's trades.
When a user deletes their account, all trades posted and interests expressed by this user should be removed from the database. However, the latter doesn't seem to work (I am also not sure if the first one works as I don't know in what order they get executed). I get the error:
The DELETE statement conflicted with the REFERENCE constraint "FKq9kr60l7n7h3yf82s44rkoe4g". The conflict occurred in database "dbi438161_i438161", table "dbo.interests", column 'user_id'.
Note: I get the same when I try to delete a trade but then the column is 'trade_id'
I do the same for the trades and roles of a user so I think it has to do with what is in my interest entity. I am using CascadeType.ALL annotation to let Hibernate remove related entities
Lists of related entities in user:
#ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(name="user_roles",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") })
private List<Role> roles = new ArrayList<>();
#Transient
#JsonIgnore
#OneToMany(cascade=CascadeType.ALL, mappedBy="user")
private List<Interest> interests = new ArrayList<>();
#Transient
#JsonIgnore
#OneToMany(cascade=CascadeType.ALL, mappedBy="user")
private List<Trade> trades = new ArrayList<>();
Interest entity:
#Entity
#Table(name = "interests")
public class Interest {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int interestId;
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
#ManyToOne
#JoinColumn(name = "trade_id", nullable = false)
private Trade trade;
private String comment;
public Interest(User user, Trade trade, String comment) {
this.user = user;
this.trade = trade;
this.comment = comment;
}
public Interest(){
}
}
For comparison, the trade entity:
#Entity
#Table(name = "trades")
public class Trade {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="trade_id")
private int tradeId;
#Column(name="wants")
private String wants;
#Column(name="offers")
private String offers;
#Column(name="date_last_modified")
private LocalDateTime lastModified;
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Transient
#JsonIgnore
#OneToMany(cascade=CascadeType.ALL, mappedBy="trade")
private List<Interest> interests = new ArrayList<>();
public Trade(String wants, String offers, User user){
this.wants = wants;
this.offers = offers;
this.user = user;
}
public Trade() {
}
}
Does anybody have an idea on what I am doing wrong here? Thanks in advance
Try to set orphanRemoval to true for the following associations:
#OneToMany(cascade=CascadeType.ALL, mappedBy="user", orphanRemoval = true)
private List<Interest> interests = new ArrayList<>();
#OneToMany(cascade=CascadeType.ALL, mappedBy="user", orphanRemoval = true)
private List<Trade> trades = new ArrayList<>();
As it is stated in the documentation:
If the child entity lifecycle is bound to its owning parent so that the child cannot exist without its parent, then we can annotate the association with the orphanRemoval attribute and dissociating the child will trigger a delete statement on the actual child table row as well.
Please also note that you should not use cascade=CascadeType.ALL for the #ManyToMany association as it explained in the documentation:
For #ManyToMany associations, the REMOVE entity state transition doesn’t make sense to be cascaded because it will propagate beyond the link table. Since the other side might be referenced by other entities on the parent-side, the automatic removal might end up in a ConstraintViolationException.

Is there an easy way using JPA/Hibernate to remove a child entity when parent is deleted without having to define a bi-directional relationship?

As the title says. Suppose I have the following entities:
#Entity
#Table
public class User {
#Id
private UUID id;
#Column(nullable = false)
private String name;
}
#Entity
#Table
public class Phone {
#Id
private UUID id;
#Column(nullable = false)
private String number;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
private User user;
}
And I don't want to define a bi-directional association - that is, I don't want to define the relation on the owner side of the relation (in the User entity). Is there an easy way to mark a Phone entity for removal if I delete its parent User?
Looking for something like CascadeType.REMOVE but on the many side of the relation. Is there such a setting available?
Use cascade = CascadeType.DELETE and orphanRemoval = true in the owning side of your association.
#Entity
#Table
public class User {
...
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) // ALL includes DELETE
private List<Phone> phones;
...
}

Java hibernate OneToOne: which side should be the owner

So i'm learning from these simple examples, there're 2 tables, USERS and USER_DETAILS, simple enough, each user has user_details and it's 1-to-1 relationship. So this sample is like this,
#Entity
#Table(name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_ID")
private long id;
#Column(name = "USERNAME", nullable = false, unique = true)
private String username;
#Column(name = "PASSWORD")
private String password;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetail userDetail;
//Setter and getter methods
}
#Entity
#Table(name = "USER_DETAILS")
public class UserDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_DET_ID")
private long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "EMAIL")
private String email;
#Column(name = "DBO")
private LocalDate dob;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "USR_ID")
private User user;
//Setter and Getter methods
}
If you look at mappedBy, it's in the User not UserDetails.
Q1: so USER is the owner, if it calls save(),
USER_DETAILS table will be updated as well ?
Q2: same examples put mappedBy in the USER_DETAILS side,
why people want to do this ?
How to determine which side to put mappedBy ?
Thanks for your help !
Q2: same examples put mappedBy in the USER_DETAILS side,
why people want to do this ?
How to determine which side to put mappedBy ?
In a bidirectional relationship, each entity has a relationship field
or property that refers to the other entity. Through the relationship
field or property, an entity class’s code can access its related
object. If an entity has a related field, the entity is said to “know”
about its related object.
There is a bidirectional one-to-one relationship in your example. Both User and UserDetail entities have a relationship field. #OneToOne annotation specified on both the entities.
For one-to-one bidirectional relationships, the owning side
corresponds to the side that contains the corresponding foreign key.
The owner of the relationship is UserDetail entity. The owner has #JoinColumn annotation to specify foreign key (USR_ID).
Inverse side of relationship (User) has mappedBy attribute.
Q1: so USER is the owner, if it calls save(),
USER_DETAILS table will be updated as well ?
In your example UserDetail is the owner. Therefore the saving process:
User user = new User(); // Ignoring the constructor parameters...
UserDetail userDetail = new UserDetail();
user.setUserDetail(userDetail);
userDetail.setUser(user);
userRepository.save(user);
You only need to save the parent. It will save the child as well.

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.

Issue in Mapping for Hibernate JPA

I have a datamodel, which has:
a User entity which has a few fields specific to 2 users in the application
another entity UserDetails, which contains details specific to one particular type of user in the application besides the fields in User entity
Both entities share the same primary key. I am new to JPA. What kind of mappings should be there between the two?
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
}
#Entity
class UserDetails{
#Id
#OneToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID")
private User user;
...
}
The above mapping gives issues on fetching UserDetails for a particular User.
It requires that both Entities share the same primary key USER_ID.
You didn't mention the issues with the above mapping. It looks OK, but I would use a separate primary key for UserDetails table.
#Entity
class UserDetails{
#Id
private int id;
#OneToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID")
private User user;
...
}
Also, it is a good practise to use bidirectional relationships, for eaiser navigation i.e. getting user details from User, you would just use user.getUserDetails(); so in User class:
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
#OneToOne(mappedBy = "user")
private UserDetails userDetails;
}
In this case use OneToOne relationship. But make sure your database table UserDetailshas foreign key relationship to User table. Use below code to implement it using JPA and Hibernate.
#Entity
class User{
#Id
#Column(name="USER_ID")
private int id;
// getters and setters
}
#Entity
class UserDetails{
#Id
#Column(name="USER_DETAILS_ID")
private int userDetailsId;
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID")
private User user;
// getters and setters
}

Categories