I'm new to Hibernate ORM and I think you can help me understand it better. More precisely, I found myself thinking if the separation of concern is very well implemented (of course it is, it's me I can't grasp... but please explain me). Let me explain: it seems to me that the main goal of hibernate is to allow developer to deal with classes forgetting about databases' peculiarities. Good! But let's examine this case:
I have an object, let's say a UserDetail having a one to may relation with an Athority object.
@Entity(name="user")
@Table(name="USERS")
public class User implements UserDetails, DomainObject {
private static final long serialVersionUID = 1L;
private long id;
private String username;
private String password;
Collection<Authority> authorities = new ArrayList<Authority>();
public User() {
super();
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique=true, nullable=false)
public long getId() {
return id;
}
//various getters & setters
@OneToMany(mappedBy="user")
public Collection<Authority> getAuthorities() {
return authorities;
}
public void setAuthorities(Collection<Authority> authorities) {
this.authorities = authorities;
}
}
here's the Authority object
@Entity(name="authority")
@Table(name="AUTHORITIES")
public class Authority implements GrantedAuthority, DomainObject{
private long id;
private User user;
private String authority; //Spring Security demands them to start with "ROLE_"
public Authority() {
super();
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id", unique=true, nullable=false)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@ManyToOne
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Column(name="authority", nullable=false)
public String getAuthority() {
return this.authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
}
ok, let's suppose I have a UserDaoImpl and AuthorityDaoImpl (here omitted for brevity). If I want to create a new UserDetails and persist it I have to do the following (it is a inizializer bean, but it really doesn't matter here):
@Component
public class Initializer {
@Autowired
@Qualifier("userDaoImpl")
private UserDao userDao;
@Autowired
@Qualifier("authorityDaoImpl")
private AuthorityDao authorityDao;
@PostConstruct
public void init()
{
if(userDao.loadUserByUsername("admin")==null)
{
System.out.println("starting initialization.");
User admin = new User();
admin.setUsername("admin");
admin.setPassword("admin");
Authority authority = new Authority();
authority.setAuthority("ROLE_ADMIN");
authority.setUser(admin);
admin.getAuthorities().add(authority);
userDao.save(admin);
authorityDao.save(authority);
System.out.println("admin user created.");
}
}
}
ok, I find strange I have to explicitly call the AuthorityDao to persist the Authority Object. If the separation of concern was well implemented I'd just had to add the authority
object to the admin
autority list and persist the admin alone. If I do that, the only entity to be persisted is the admin.
Don't you think the same? Am I missing something?
Yes. You are missing one thing. Just add cascade = CascadeType.ALL
or cascade = CascadeType.PERSIST
(select as suitable) in your oneToMany
mapping in Admin
entity mapping as below. Once done, saving adimn
will save authority
as well.
@OneToMany(mappedBy="user", cascade = CascadeType.ALL)
public Collection<Authority> getAuthorities() {
return authorities;
}
Please find more details around cascade
types and settings here: Hibernate Cascade.
This is required to support different behavior on the child entities. Say for example, your authority is a master table i.e. mapping from table such as country, currency etc. Here you will not like to persist/delete currency, country along with the parent object. Being a generic framework, it has to support several aspects of the requirements.