Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

Actually, automatic persistence of associated objects can be enabled in the mapping in two different ways:

To express what UML calls composition (i.e. the depending object can not exist independently of the referring object, not be referred to by other objects), you can make it an @Embeddable. Hibernate will then insert, update, and delete the dependent object along with (the association to) its owning object.

To express what UML calls aggregation (i.e. the referred object has an identity of its own and an independent lifecycle), you make the referred object an @Entity. You can instruct JPA to automatically cascade persistence operations along an association by specifying its cascade attribute.

And of course, any objects loaded by the persistence context will detect changes, and automatically write them to the database when the transactions commits.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top