I have a one to many relation on post class, and on the relation table I have one to one relation with user. Everything works find, but i want to be able to remove the relation, keeping the user entity, is that possible?
At this moment with the annotation orphanRemoval = true when I remove from post Detail list an element, this its removed from post_details table but the user is removed too.
#Entity
#Table(name = "ta_post")
public class Post{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private Date fcDate;
#OneToMany(mappedBy="post", cascade=CascadeType.ALL, orphanRemoval = true)
private List<PostDetails>;
}
#Entity
#Table(name = "ta_user")
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int mail;
}
#Entity
#Table(name = "ta_post_details")
public class PostDetails{
private int id;
#ManyToOne
#JoinColumn(name="post_id")
private Post post;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="user_id")
private User user;
private String postComments;
}
You must remove the CascadeType.ALL from the PostDetails. If you want to be able to change the User through the PostDetails, you can set the CascadeType to PERSIST or MERGE. If you want to create a PostDetail along with an User, you need to include the CascadeType CREATE.
I'd guess you are creating the user somewhere else and you just associate one with a Post, so removing the CascadeType.ALL should be enough to not delete your User from the database.
Related
2 entities that I have: Country and User
#Entity(name = "Country")
#Table(name = "countries")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true)
private List<User> users = new ArrayList<>();
}
#Entity(name = "User")
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private boolean removed;
}
Entity User has an attribute, removedtype boolean and we need to skip/ignore all User's that have removed equals true.
Does Hibernate provide any suitable mechanism to achieving my goal?
P.S: Google says that potentially I can use annotations like: #JoinColumn, #JoinColumnOrFormula, but based on docs that I have read, annotations mentioned above belong to #ManyToOne scenario, in my particular case I have #OneToMany relation.
With hibernate, using #Where on the entity should do the trick. This will prevent any user to be loaded which has the removed flag set to true. You might find more information in the hibernate docs
If you only want this to be on the collection, you can add the annotation on the relationship
#Entity(name = "Country")
#Table(name = "countries")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true)
#Where( clause = "removed = false" ) // <- here
private List<User> users = new ArrayList<>();
}
Alternatively, if you don't want to load any removed user at all, the annotation can be added to the class.
#Entity(name = "User")
#Table(name = "users")
#Where( clause = "removed = false" ) // <- here
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private boolean removed;
}
A word of caution, I haven't used this, but I assume that if you have other entities with linked to a user which has the flag set to true, you'll need to update the annotations to allow nulls.
For example, imagine an ecomerce site, an Order is linked to a user. Loading an Order linked to a removed user will fail, or you can ammend the annotations so it returns an order with a null user. I hope this makes sense!
I have this problem and I'd appreciate any help...
I have a User entity. A user has a Role (a many to one relationship). And a role has a list of permissions (the many to many relationshp I'm having trouble with).
In my code, I am selecting a single user out of the database, by username.
When I retrieve the user, the user's role is there inside of it. But inside the role, there should be a list of permissions. There should be 4 permissions, but every time, I am only getting one element back in the set.
I have queried the database correctly, and there are indeed 4 permissions attached to that role, so the problem isnt there.
UserEntity:
#Table(name = "users")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String username;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "role_id")
private RoleEntity role;
}
RoleEntity:
#Table(name = "roles")
public class RoleEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String name;
private String description;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "roles_permissions", joinColumns = #JoinColumn(name = "permission_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<PermissionEntity> permissions = new HashSet<>();
}
And here is my repository. I'm calling this method from a service, and am just getting back what I described above.
#Repository
public interface UserRepository extends CrudRepository<UserEntity, String> {
Optional<UserEntity> findByUsername(String username);
}
In my database, I have a table called 'roles_permissions' with the fields role_id and permission_id. There are four records in here. role_id is '1' for all of them, and its linked to permissions 1,2,3,4.
In the users table, there is a field for role_id. And the user that I'm selecting has this field populated with 1.
Okay, nevermind. I've been working on this for a while, and I figured it out as soon as I posted this!
In the #JoinTable annotation, I had "role_id" and "permission_id" the wrong way around!
In a db, I have User and Role entities. The share a many-to-many relation as a Role entity can be assigned to multiple User entities and on the other hand a User entity can be assigned to multiple Role entities.
My entity classes look like this
UserEntity
#Entity
public class UserEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(unique = true, nullable = false)
private String username;
#ManyToMany
private Set<RoleEntity> roles;
...
}
RoleEntity
#Entity
public class RoleEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(unique = true, nullable = false)
private String name;
#ManyToMany(mappedBy = "roles")
private Set<UserEntity> users;
...
}
With this configuration I am able to map the entities with each other. I am also able to delete a User entity. But I am not able to delete a Role entity as long as a relation exists.
If I add cascade = CascadeType.REMOVE the Rolegets deleted, but with it the User too of course.
To only way to get this working currently is to define a #JoinTable on both sides. But this seems more like a workaround. What am I doing wrong? As this is a regular use case, there got to be solution to this, although I haven found it yet...
You need the join table, it's not a work around. Remember you are mapping your object oriented model to a relational model. The only way to express many-to-many relationship in the relational model is defining a #JoinTable.
UPDATE: Adding comment in the answer
You sould define the #JoinTable just in one entity, for example UserEntity and mappedBy="roles" in RolesEntity inherits the definitions of #JoinColumn and #JoinTable names.
Then you need to define the cascade operations you want to perform in both sides of the relationship.
In RoleEntity
#ManyToMany(mappedBy = "roles")
private Set<UserEntity> users;
In UserEntity
#ManyToMany
#JoinTable(...)
private Set<RoleEntity> roles;
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.
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
}