简体   繁体   中英

Is it a good idea to use Hibernate for representing table relations?

I am trying to connect to a mysql db from java using hibernate. I am trying to understand whether it really worth using an ORM such as hibernate for relations or not. Especially specfying relationships with annotations seems quite irritating to me. So for a friendship table I would like to see the friendship requests of a particular user by using the foreign key from a users table.

In hibernate classes for helper table holds a field which represents the main table too. So instead of keeping the relation with a simple int , it holds a User class as a primary field. This might be useful, if you need to access the user object but in some cases you only need the foreign key id.

I put the sample code I have written for two tables, Users and UserFriendRequests. Is this the best approach to represent the following two tables? I feel like this is quite overkill for representing such basic tables. I would prefer using Hibernate just for connection and representing tables individually and handle relations manually. Would you recommend this approach? I would appreciate if you can share your ideas and documents about best practices.

Users table have the following columns

  • userId primary, auto increment
  • facebookId unique
  • username
  • createdAt date
  • lastLogin date
  • lastNotifiedAt date

UserFriendRequests table have the following columns:

  • firstUser foreignkey of userId from Users table
  • secondUser foreignkey of userId from Users table
  • PrimaryKey(firstUser, secondUser)

Representation of User table

@Entity
@Table(name = "Users", catalog = "example_schema", uniqueConstraints = {
@UniqueConstraint(columnNames = "userId"),
@UniqueConstraint(columnNames = "facebookId")})
public class User implements Serializable {

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "userId", unique = true, nullable = false)
private int userId;
@Column(name = "facebookId", unique = true, nullable = false)
private String facebookId;
@Column(name = "userName", nullable = false)
private String userName;
@Column(name = "createdAt", nullable = false)
@Temporal(javax.persistence.TemporalType.DATE)
private Date createdAt;
@Column(name = "lastLogin")
@Temporal(javax.persistence.TemporalType.DATE)
private Date lastLogin;
@Column(name = "lastNotifiedAt")
@Temporal(javax.persistence.TemporalType.DATE)
private Date lastNotifiedAt;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.firstUser") // I would prefer to fill these relations manually
private List<UserFriendRequest> userFriendRequests = Lists.newArrayList();
@Transient
private boolean newUser;

public User() {
    this.createdAt = new Date();
    this.newUser = false;
}

public User(int userId) {
    this();
    this.userId = userId;
}

public User(String facebookId, String userName) {
    this();
    this.facebookId = facebookId;
    this.userName = userName;
}

public User(int userId, String facebookId, String userName) {
    this(facebookId, userName);
    this.userId = userId;
}

public int getUserId() {
    return userId;
}

public void setUserId(int userId) {
    this.userId = userId;
}

public String getFacebookId() {
    return facebookId;
}

public void setFacebookId(String facebookId) {
    this.facebookId = facebookId;
}

public boolean isNewUser() {
    return newUser;
}

public void setNewUser(boolean newUser) {
    this.newUser = newUser;
}

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

public Date getCreatedAt() {
    return createdAt;
}

public void setCreatedAt(Date createdAt) {
    this.createdAt = createdAt;
}

public Date getLastLogin() {
    return lastLogin;
}

public void setLastLogin(Date lastLogin) {
    this.lastLogin = lastLogin;
}

public Date getLastNotifiedAt() {
    return lastNotifiedAt;
}

public void setLastNotifiedAt(Date lastNotifiedAt) {
    this.lastNotifiedAt = lastNotifiedAt;
}

public List<UserFriendRequest> getUserFriendRequests() {
    return userFriendRequests;
}

public void setUserFriendRequests(List<UserFriendRequest> userFriendRequests) {
    this.userFriendRequests = userFriendRequests;
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 53 * hash + this.userId;
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final User other = (User) obj;
    if (this.userId != other.userId) {
        return false;
    }
    return true;
}

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}

Representation of UserFriendRequests table

@Entity
@Table(name = "UserFriendRequests", catalog = "example_schema")
public class UserFriendRequest implements Serializable {

@Embeddable
public static class UserFriendRequestKey implements Serializable {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "firstUser", nullable = false)
    //Instead of user class I would prefer to keep only the int field. If I would need the user object I would handle it myself.
    private User firstUser;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "secondUser", nullable = false)
    private User secondUser;

    public UserFriendRequestKey() {
    }

    public UserFriendRequestKey(User firstUser, User secondUser) {
        this.firstUser = firstUser;
        this.secondUser = secondUser;
    }

    public User getFirstUser() {
        return firstUser;
    }

    public void setFirstUser(User firstUser) {
        this.firstUser = firstUser;
    }

    public User getSecondUser() {
        return secondUser;
    }

    public void setSecondUser(User secondUser) {
        this.secondUser = secondUser;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 89 * hash + Objects.hashCode(this.firstUser);
        hash = 89 * hash + Objects.hashCode(this.secondUser);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final UserFriendRequestKey other = (UserFriendRequestKey) obj;
        if (!Objects.equals(this.firstUser, other.firstUser)) {
            return false;
        }
        if (!Objects.equals(this.secondUser, other.secondUser)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
}

@Id
private UserFriendRequestKey id;
@Column(name = "requestedAt", nullable = false)
@Temporal(javax.persistence.TemporalType.DATE)
private Date requestedAt;

public UserFriendRequest() {
}

public UserFriendRequest(UserFriendRequestKey id) {
    this.id = id;
    this.requestedAt = new Date();
}

public UserFriendRequestKey getId() {
    return id;
}

public void setId(UserFriendRequestKey id) {
    this.id = id;
}

public Date getRequestedAt() {
    return requestedAt;
}

public void setRequestedAt(Date requestedAt) {
    this.requestedAt = requestedAt;
}

@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}

Hibernate has a steep learning curve but it also has the following advantages:

  1. Insert/Updates are easier due to "dirty checking". Once you have the service in place, you can easily add new fields without changing a line in your service. You just need to add new columns and populate those and Hibernate will take care of the persistence part.
  2. Hibernate can solve the "lost update" problem because of it's optimistic locking concurrency control.
  3. Integration testing is easier, since you can generate the schema automatically for your in-memory database (HSQLDB, H2, Derby)
  4. It has a caching plug-in support (through third party 2nd level caching providers), some providers allowing you to have both "transactional" and "clustered" caches.
  5. It has a built-in AUDIT support (Envers)

So it's not a 'default' persistence solution, since there are millions of web apps written in PHP with no ORM framework that are successfully running in production.

I think Hibernate has much more sense for enterprise applications where caching, auditing, concurrency reliability are mandatory non-functional requirements.

Hibernate used for Object relational mapping.You write HQL query,If you are using hibernate.We used hibernate in different approach.let me tell how to do.

Using hibernate plugin,you can genrate pojo classes for every table present in the DB.So no need to write a pojo class from your side and many xml related files also.You must need one persisten.xml file on your project.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM