Spring Data Jpa 复合主键

前言

这次大创有个需求,在数据库建表时发现,user表与project表的关系表 user_project的主键为复合主键:

CREATE TABLE user_project(
  user_id            INT(20),
  project_id         INT(20),
  timestamp         VARCHAR (50),
  donate_money       DOUBLE(10,2),
  PRIMARY KEY (user_id,project_id)
);

在网上看了几篇博客,以及在spring boot干货群咨询(感谢夜升额耐心解答)过后总算是做出来了。这里做个总结,方便日后查阅。


正文

这里采用@IdClass注解的方式来实现复合主键;

思路

  1. 编写一个复合主键类UserProjectMultiKeysClass;
  2. 通过@IdClass注释在实体中标注复合主键;
  3. 可以通过EntityManager获取数据,或者是直接在Repository 里写方法;

实现

复合主键类

package com.hzy.Model;

import java.io.Serializable;

/**
 * Created by huangzhenyang on 2017/9/7.
 * UserProject的复合主键类
 *
 * @Param userId
 * @Param projectId
 * @Param timestamp
 * 由这三个共同组成复合主键
 */
public class UserProjectMultiKeysClass implements Serializable {
    private Integer userId;
    private Integer projectId;
    private String timestamp;

    //Constructor
    public UserProjectMultiKeysClass() {
    }

    public UserProjectMultiKeysClass(Integer userId, Integer projectId, String timestamp) {
        this.userId = userId;
        this.projectId = projectId;
        this.timestamp = timestamp;
    }

    //Setter and Getter
    public Integer getUserId() {
        return userId;
    }

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

    public Integer getProjectId() {
        return projectId;
    }

    public void setProjectId(Integer projectId) {
        this.projectId = projectId;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    //  ***重写hashCode与equals方法***  划重点!
    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + ((userId == null) ? 0 : userId.hashCode());
        result = PRIME * result + ((projectId == null) ? 0 : projectId.hashCode());
        result = PRIME * result + ((timestamp == null) ? 0 : timestamp.hashCode());
        return result;
    }

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

        final UserProjectMultiKeysClass other = (UserProjectMultiKeysClass)obj;
        if(userId == null){
            if(other.userId != null){
                return false;
            }
        }else if(!userId.equals(other.userId)){
            return false;
        }
        if(projectId == null){
            if(other.projectId != null){
                return false;
            }
        }else if(!projectId.equals(other.projectId)){
            return false;
        }
        if(timestamp == null){
            if(other.timestamp != null){
                return false;
            }
        }else if(!timestamp.equals(other.timestamp)){
            return false;
        }

        return true;
    }
}

注意:
复合主键类必须满足:
1. 实现Serializable接口;
2. 有默认的public无参数的构造方法;
3. 重写equalshashCode方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity时,是根据equals的返回值来判断的。hashCode方法返回当前对象的哈希码;

实体类

package com.hzy.Model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import java.io.Serializable;

/**
 * Created by huangzhenyang on 2017/9/7.
 * 
 */
@Entity
@Table(name = "user_project")
@IdClass(UserProjectMultiKeysClass.class)
public class UserProject  implements Serializable {
    private double donateMoney;
    private Integer userId;
    private Integer projectId;
    private String timestamp;

    @Id
    public Integer getUserId(){
        return this.userId;
    }

    @Id
    public Integer getProjectId(){
        return this.projectId;
    }

    @Id
    public String getTimestamp(){
        return this.timestamp;
    }

    //getter and setter
    public double getDonateMoney() {
        return donateMoney;
    }

    public void setDonateMoney(double donateMoney) {
        this.donateMoney = donateMoney;
    }

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

    public void setProjectId(Integer projectId) {
        this.projectId = projectId;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    @Override
    public String toString() {
        return "UserProject{" +
                "donateMoney=" + donateMoney +
                ", userId=" + userId +
                ", projectId=" + projectId +
                ", timestamp='" + timestamp + '\'' +
                '}';
    }
}

注意:
1. @IdClass标注用于标注实体所使用主键规则的类;
2. 在实体中同时标注主键的属性,比如这段代码中的userId,projectId以及timestamp


获取数据

  1. 方法一: 通过EntityManager获取,比如方法testUserProjectRepository()
  2. 方法二:通过Repository获取;这里记得在extends JpaRepository时把id的主键类指定为复合主键类UserProjectMultiKeysClass
public interface UserProjectRepository extends JpaRepository<UserProject,UserProjectMultiKeysClass>{
    // 根据用户Id,找出用户参与的所有UserProject
    // TEST PASS
    List findByUserId(Integer userId);

    // 根据项目id,找出参与项目的所有UserProject
    // TEST PASS
    List findByProjectId(Integer projectId);

    // 根据用户id和项目id 找出所有的UserProject
    // TEST PASS
    List findByUserIdAndProjectId(Integer userId,Integer projectId);
}

单元测试的代码

   package com.hzy;

import com.hzy.Model.UserProject;
import com.hzy.Model.UserProjectMultiKeysClass;
import com.hzy.Repository.UserProjectRepository;
import com.hzy.Service.UserProjectService;
import com.hzy.Service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.util.List;

/**
 * Created by huangzhenyang on 2017/9/8.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserProejctRepositoryTest {
    @Autowired
    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private UserProjectRepository userProjectRepository;

    @Test
    public void testUserProjectRepository(){
        UserProjectMultiKeysClass userProjectMultiKeysClass =
                new UserProjectMultiKeysClass(1, 1, "2017-09-08");
        UserProject userProject = entityManager.find(UserProject.class,userProjectMultiKeysClass);
        System.out.println(userProject.toString());
    }


    @Test
    public void testFindByUserId(){
        List userProjects = userProjectRepository.findByUserId(1);
        for(UserProject userProject:userProjects){
            System.out.println(userProject.toString());
        }
    }

    @Test
    public void testFindByProjectId(){
        List userProjects = userProjectRepository.findByProjectId(1);
        for(UserProject userProject:userProjects){
            System.out.println(userProject.toString());
        }
    }

    @Test
    public void testFindByUserIdAndProjectId(){
        List userProjects = userProjectRepository.findByUserIdAndProjectId(1,1);
        for(UserProject userProject:userProjects){
            System.out.println(userProject.toString());
        }
    }
}

你可能感兴趣的:(Spring Data Jpa 复合主键)