【问题标题】:Spring: Save object with foreign keys with a POST requestSpring:使用 POST 请求使用外键保存对象
【发布时间】:2017-06-03 04:08:58
【问题描述】:

我对 Spring (REST) 有点陌生,我正在构建一个简单的 REST Web 服务。我使用 RestController 来映射 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);
}

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

{
    "gradeType": "REGULAR",
    "grade": "10",
    "passed": 1,
    "userId": 1,
    "exam_id": 1,
    "user_id": 3
}

问题是,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"
}

我该如何解决这个问题?我听说过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() {
    }

还有我的存储库...

@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;
    }
}

谢谢

【问题讨论】:

  • 能否请您也添加您的存储库类?
  • @SrikanthA 当然!傻我。我已经添加了

标签: java json spring hibernate rest


【解决方案1】:

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

是的,您可以使用 JpaRepository 执行此操作。您可以开始添加Interface
public interface GradeRepository extends PagingAndSortingRepository&lt;Grade, Long&gt;UserExam 相同
然后当你 POST 你的 Grade 在你的控制器中时(我会建议一个 Service
1.创建new Grade()
2. 使用setters 链接你的UserExam 通过@Autowire-ing 你的UserRepositoryExamRepository 并调用findById
3.然后使用settersPOST获取其他字段
4. 从您的@Autowired GradeRepository 拨打.save(grade)

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

此外,我强烈建议您不要通过 HTTP 直接传递实体,而是使用 DTOs 并且在您的 Grade json 中永远不要传递 exam id。尝试通过其他字段查找考试,而不是 table id(例如:findByName)

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

【讨论】:

  • 谢谢,这已经是一个巨大的帮助。我试图Autowire repo 介绍我的控制器,但我是这个问题: 描述:HvA.Controllers.GradeController 中的字段gradeRepository 需要一个找不到的“HvA.Repositories.GradeRepository”类型的bean。行动:考虑在你的配置中定义一个“HvA.Repositories.GradeRepository”类型的bean。
  • 确保你是@ComponentScan("com.pkg.repos")-ing 你的repos。你可能也需要@EnableJpaRepository("com.pkg.repos")
  • 在哪个文件中?我的主要Application.java?
  • 是的,在你的 Application 类之上
  • @AlexandruHodis 为什么不建议您通过考试 ID?如果客户想要发布一个新成绩,他们不想通过传递父考试的 id 来做到这一点吗? (忽略将考试 ID 包含在 URL 中的可能性)
猜你喜欢
  • 2021-03-02
  • 2017-08-18
  • 2013-03-10
  • 2016-04-06
  • 1970-01-01
  • 2020-08-01
  • 2021-02-13
  • 1970-01-01
相关资源
最近更新 更多