Hibernate: @JoinTable with intermediary table

The abstract application’s scheme below which uses Hibernate as ORM.在这里插入图片描述
Every modern application has some domain models. They represent some objects such as cars, books, contacts, customers etc. For each domain model exists table in database. Every column from table has an appropriate field in the domain model.
As you understand POJOs are used for the persistence of data which are obtained in runtime of the application. POJO contains fields and a set of getters / setters for the fields. This implies that you can perform all range of CRUD operations.

Let’s go back to the scheme. In the center you can see hibernate.cfg.xml, its role is to contain all Hibernate properties (e.g. database url, database user, password, sql dialect etc.). Also if you use xml mapping for the POJO, you need to put separate links on xml-mapping files. XML-mapping is illustrated on the scheme with the dashed arrows.

### Example of hibernate.cfg.xml:

<hibernate-configuration>
    <session-factory>
    <!-- SET OF PROPERTIES -->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibnatedb</property>
    <property name="hibernate.connection.username">hibuser</property>
    <property name="hibernate.connection.password">root</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    <property name="connection.pool_size">1</property>
    <property name="show_sql">true</property>
    <!-- Mapping files -->
    <mapping resource="person.hbm.xml"></mapping>
    <mapping resource="contact.hbm.xml"></mapping>
    <mapping resource="company.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

Every “mapping” tag contains link to another XML-file with rules of mapping domain object fileds to table columns. If you use the annotation-based configuration of the POJOs, your hibernate.cfg.xml file will contain “mapping” tags with “class” attribute instead of “resource”. Hence you don’t need to create separate xml-files for every domain model, because you will annotate required fields directly in classes.
Both of the approaches have its own cons and pros, but that’s out of the article’s scope.

Further you can instantiate SessionFactory based on hibernate.cfg.xml. Usually it is one per application. Then you can create a Session object and perform CRUD operations… Hibernate interacts with DB via JDBC API.

Summary
Everything you have read above is a rough overview of Hibernate and its functional principles of functionality. I called it rough, because it doesn’t contain a lot of details (e.g. Transactions). For more information you can read books and documentation. The last one is perfect.
In the second part, I will show you how to develop simple application using Hibernate.

==============================================================
Now I want to talk about one of the most important features of Hibernate – associations. An association represents a relationship between two tables in a database. So let’s go further because great things wait for us.

Every modern RDBMS supports relationships. There are four known types of relationships:

  • one to one
  • one to many
  • many to one
  • many to many

I will not stop giving in detail every type because they are out of the post theme. As mentioned above, Hibernate can programmatically provide a way of relations between DB tables in an application. I’m going to consider just annotation based approach of associations, XML approach will be omitted. So here are four appropriate annotations which help to obtain appropriate types of DB table relationships:

  • @OneToOne
  • @OneToMany
  • @ManyToOne
  • @ManyToMany
    Everything seems to be very simple and trivial, but if we face the truth we will soon understand that, setting up correct association between two entities is one of the hardest things in Hibernate. There are a lot of reasons: plenty of settings which you can use within setting up, a lot of details which you need to keep in your mind while obtaining an association.

There is one strange thing happening to most of developers – associations can be of two types. Hibernate provides unidiractional and bidirectional associations. Don’t try to make a parallel with RDBMS, because they have relations and with their help you can access data from both sides of relation. Meanwhile in Hibernate you can setup association which will be unidirectional and will give an access to data just for one of entities (owner side). This is possible due to references between classes.

Also Hibernate supports primary key association and foreign key association. You can specify a behaviour of records in tables with the help of cascade attribute. So as you can see you have a wide range of possibilities while developing with Hibernate. In the following articles I’m going to provide some examples with MySQL and OneToOne mapping (unidirectional and bidirectional).

==============================================================

There are a lot of articles about Hibernate associations in the internet and particularly on my blog. But JPA provides numerous combinations of associations, so it’s not strange that we still see new posts about this or that kind of association. Today I want to examine situation with the @JoinTable annotation and intermediary table. For the tutorial I’ll use MySQL, Hibernate as implementation of JPA and Maven.

Today’s example will be based on a simple situation – user role service. That means that I’m going to work with two entities: User, Role. Every user can has just one role. So in the database I need to create one table for the users, one table for the roles and the third one for the mapping of the roles to the users. The last table, as you understand, plays role of intermediary table.

在这里插入图片描述
The admin record will be with the id = 1, and the moderator record will be with the id = 2.
Now let’s move to a java code of the classes which will represent the tables:

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
 
@Entity
@Table(name="users")
public class User {
 
    @Id
    @GeneratedValue
    private Integer id;
     
    private String login;
     
    private String password;
     
    @OneToOne(cascade=CascadeType.ALL)
    @JoinTable(name="user_roles",
    joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
    inverseJoinColumns={@JoinColumn(name="role_id", referencedColumnName="id")})
    private Role role;
     
    public User(String login, String password) {
        this.login = login;
        this.password = password;
    }
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getLogin() {
        return login;
    }
 
    public void setLogin(String login) {
        this.login = login;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public Role getRole() {
        return role;
    }
 
    public void setRole(Role role) {
        this.role = role;
    }
     
}

In this class you noticed that I applied a lot of annotations to the Role property. The @OneToOne annotation was used since users table is in “one to one” relationship with the user_roles table. The @JoinTable annotation indicates that we will interact with the intermediary table (user_roles) and further you can see settings of the relationship including mapping of columns.

The joinColumns attribute is responsible for the columns mapping of the owning side. The name attribute contains the column name of the intermediary table, the referencedColumnName attribute contains the primary key column name (in our case the primary key column of the user table is id) of the owning side.

The inverseJoinColumns attribute is responsible for the columns mapping of the inverse side. Here is everything is similar as in the explanation above, just with the one distinction – you need to apply this to the roles and user roles tables.

import java.util.List;
 
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
 
@Entity
@Table(name="roles")
public class Role {
 
    @Id
    @GeneratedValue
    private Integer id;
     
    private String role;
     
    @OneToMany(cascade=CascadeType.ALL)
    @JoinTable(name="user_roles",
    joinColumns={@JoinColumn(name="role_id", referencedColumnName="id")},
    inverseJoinColumns={@JoinColumn(name="user_id", referencedColumnName="id")})
    private List<User> userList;
     
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }
    public List<User> getUserList() {
        return userList;
    }
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
     
}

In the Role entity, almost all annotations are the same as in the previous one. Pay your attention to @OneToMany annotation. Hence, appears property of collection type (private List userList).

Let’s see how this code can work:

public class DemoFirst {
 
    public static void main(String[] args) {
 
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
         
        Role role = (Role) session.get(Role.class, 2);
 
        User user = new User("Fruzenshtein", "qwerty");
        user.setRole(role);
         
        session.save(user);
         
        session.getTransaction().commit();
         
        session.close();
 
    }
}

The result of the code execution is:

Hibernate: select role0_.id as id2_0_, role0_.role as role2_0_ from roles role0_ where role0_.id=?
Hibernate: insert into users (login, password) values (?, ?)
Hibernate: insert into user_roles (role_id, user_id) values (?, ?)

The @JoinTable annotation is a powerful feature of the Hibernate, it
can be applicable to many situations to make your life easier. It can
be used with two tables and with three.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值