Spring:使用 POST 请求保存带有外键的对象

Roe*_*ker 6 java rest spring json hibernate

我对 Spring (REST) 有点陌生,我正在构建一个简单的 REST web 服务。我使用 aRestController来映射 HTTP 请求。我使用这个简单的方法来接受一个 POST 请求:

@RequestMapping(value = "/grade/create", method = RequestMethod.POST)
public ResponseEntity<Grade> createGrade(@RequestBody Grade grade)
{
    dao.createGrade(grade);

    return new ResponseEntity<Grade>(grade, HttpStatus.OK);
}
Run Code Online (Sandbox Code Playgroud)

dao在这种情况下是一个带有@Repository注释的类。一个请求应该是这样的:

{
    "gradeType": "REGULAR",
    "grade": "10",
    "passed": 1,
    "userId": 1,
    "exam_id": 1,
    "user_id": 3
}
Run Code Online (Sandbox Code Playgroud)

问题是,它Grade有 2 个外键,用于用户和考试。我希望能够只传递外部实体的 ID,让 Hibernate 处理其余的事情。但是,目前我得到这个作为回应:

{
  "timestamp": 1484758525821,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "org.springframework.dao.InvalidDataAccessResourceUsageException",
  "message": "could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement",
  "path": "/grade/create"
}
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?我听说过 a JpaRepository,我可以用它来完成这个吗?

我的Grade模态如下:

@Entity
@Table(name = "grades")
@NamedQueries(value = {
        @NamedQuery(name = "Grade.get", query = "SELECT c FROM Grade c WHERE id = :id"),
        @NamedQuery(name = "Grade.getAll", query = "SELECT c FROM Grade c"),
        @NamedQuery(name = "Grade.getAllByUser", query = "SELECT g FROM Grade g INNER JOIN Exam e ON g.exam.id = e.id INNER JOIN Course c ON e.course.id = c.id WHERE g.user.id = :id"),

})
public class Grade {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "type")
    private String gradeType;

    @Column(name = "grade")
    private String grade;

    @Column(name = "passed")
    private int passed;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "exam_id")
    private Exam exam;

    private int examId;

    private int userId;

    public Grade(int id, String gradeType, String grade, int passed, User user, Exam exam)
    {
        setId(id);
        setGradeType(gradeType);
        setGrade(grade);
        setPassed(passed);
        setUser(user);
        setExam(exam);
    }

    public Grade() {
    }
Run Code Online (Sandbox Code Playgroud)

还有我的仓库...

@Repository
public class GradeDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public List<Grade> getallGrades() {
        return em.createNamedQuery("Grade.getAll", Grade.class)
                .getResultList();
    }

    public List<Grade> getLimitedGradesByUser(int limit, int user_id) {
        return em.createNamedQuery("Grade.getAllByUser", Grade.class)
                .setParameter("id", user_id)
                .setMaxResults(limit)
                .getResultList();
    }

    @Transactional
    public Grade getGrade(int id) {
        return em.createNamedQuery("Grade.get", Grade.class).setParameter("id", id).getSingleResult();
    }

    @Transactional
    public Grade createGrade(Grade grade) {
        grade = em.merge(grade);
        em.persist(grade);

        return grade;
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Ale*_*dis 4

我该如何解决这个问题?我听说过有关 JpaRepository 的信息,我可以用它来完成此任务吗?

是的,您可以使用 JpaRepository 来完成此操作。您可以开始添加一个Interface
public interface GradeRepository extends PagingAndSortingRepository<Grade, Long>,同样适用于UserandExam
然后当您POSTGrade控制器中时(我建议Service为此添加一个 )
1. 创建一个new Grade()
2.通过-ing 您的and并调用setters来链接您的and 3. 然后从中获取其他字段您使用4. 从您的 电话UserExam@AutowireUserRepositoryExamRepositoryfindById
POSTsetters
.save(grade)@Autowired GradeRepository

请注意 和User应该Exam已经存在于 中DB才能链接它们

另外,我强烈建议您永远不要通过HTTPuse传递直接实体DTOs,并且在Gradejson 中永远不要传递exam id. 尝试通过其他字段查找考试,而不是table id(例如:findByName)

我使用 JPA 和 Security 实现了一个功能齐全的 SpringBoot 应用程序,您可以看看https://github.com/hodispk/internship