【问题标题】:Java JPA Foreign Key Reference not being saved未保存 Java JPA 外键引用
【发布时间】:2019-11-06 11:33:04
【问题描述】:

我正在学习 SpringBoot 并尝试创建一个简单的 API。使用 H2 作为数据层。

我的表结构如下

DROP TABLE IF EXISTS Users;
DROP TABLE IF EXISTS Cards;
CREATE TABLE Users(USER_ID INT PRIMARY KEY,
              NAME VARCHAR(255) NOT NULL,
              USERNAME VARCHAR(255) NOT NULL,
              PASSWORD VARCHAR(255) NOT NULL,
              IS_ADMIN BOOL);

insert into Users values(10001,'Administrator', 'admin', 'admin', true);

CREATE TABLE Cards(CARD_ID INT PRIMARY KEY,
              NUMBER VARCHAR(20) NOT NULL,
              EXPIRY VARCHAR(5) NOT NULL,
              CVV INT,
              USER INT,
              foreign key (USER) references Users(USER_ID)
);

我的 CreditCard 实体如下所示。

package sprintboot;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
@Entity
@Table(name = "CARDS")
@ApiModel(description = "the Credit Card object")
public class CreditCard {

    @ApiModelProperty(notes = "The DB ID of card")
    private @Column(name = "CARD_ID") @Id @GeneratedValue Long card_id;

    @NotBlank(message = "Credit card number is mandatory")
    @ApiModelProperty(notes = "The number of credit card", required = true)
    private @Column(name = "NUMBER") String number;

    @NotBlank(message = "Credit card expiry is mandatory")
    @ApiModelProperty(notes = "The expiry of credit card", required = true)
    private @Column(name = "EXPIRY") String expiry;

    @NotNull(message = "Credit card cvv is mandatory")
    @ApiModelProperty(notes = "The cvv of credit card", required = true)
    private @Column(name = "CVV") Integer cvv;

    @ApiModelProperty(notes = "The owner user of credit card")
    @ManyToOne
    @JoinColumn
    private User user;

    public CreditCard() {}

    public CreditCard(String number, String expiry, Integer cvv, User user) {
        this.number = number;
        this.expiry = expiry;
        this.cvv = cvv;
        this.user = user;
    }

    @Override
    public String toString() {
        return "{number: " + this.number + ", expiry: " + this.expiry + ", cvv: " + this.cvv + ", user: " + this.user + "}";
    }
}

我的用户实体如下所示

package springboot;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.util.List;

@Data
@Entity
@Table(name = "USERS")
@ApiModel(description = "the USER object")
public class User {

    @ApiModelProperty(notes = "The id of User")
    private @Column(name = "USER_ID") @Id @GeneratedValue Long user_id;

    @ApiModelProperty(notes = "The name of User")
    private @Column(name = "NAME") String name;

    @ApiModelProperty(notes = "The username of User", required = true)
    @NotBlank(message = "Username is mandatory")
    private @Column(name = "USERNAME") String username;

    @ApiModelProperty(notes = "The password of User", required = true)
    @ValidPassword(message = "Password is mandatory")
    private @Column(name = "PASSWORD") String password;

    @ApiModelProperty(notes = "The admin status of User")
    private @Column(name = "IS_ADMIN") boolean isAdmin;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<CreditCard> cards;

    public User() {}

    public User(String name, String username, String password, boolean isAdmin) {
        this.name = name;
        this.username = username;
        this.password = password;
        this.isAdmin = isAdmin;
    }

    @Override
    public String toString() {
        return "{id: " + this.getUser_id() + ", username: " + this.getUsername() + ", isAdmin: " + this.isAdmin() + "}";
    }
}

所以信用卡将包含一个用户。一个用户可以包含许多信用卡。我遇到的问题是,当我尝试保存信用卡记录时。它会引发以下错误。

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.In
validDataAccessResourceUsageException: could not prepare statement; SQL [insert into cards (cvv, expiry, number, user_user_id, card_id) values (?, ?, ?, ?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement] with root

原因

org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "USER_USER_ID" not found; SQL statement:
insert into cards (cvv, expiry, number, user_user_id, card_id) values (?, ?, ?, ?, ?) [42122-199]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:451) ~[h2-1.4.199.jar:1.4.199]

我已尝试搜索并遵循多个教程,但无法使其正常工作。谁能指出我哪里错了。

信用卡实体的保存方法如下。

public CreditCard upsertCC(
        CreditCard card,
        String jwtToken
) throws UnauthorizedException {
    User user = this.getUserFromJWTToken(jwtToken);
    log.info(user.toString());
    card.setUser(user);
    this.ccRepo.save(card);
    this.ccRepo.flush();
    card.setUser(null);
    return card;
}

其中 getUserFromJWTToken 方法从 h2 表中返回一个 User 对象。

任何建议

【问题讨论】:

  • 很明显是org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "USER_USER_ID" not found。看来列映射是错误的。

标签: java spring-boot jpa h2


【解决方案1】:

异常其实是Column "USER_USER_ID" not found;

如果您看到查询,insert into cards (cvv, expiry, number, user_user_id, card_id) values (?, ?, ?, ?, ?),提到 user_user_id 不是列名

所以问题是您没有在CreditCard 实体中将列名提到为user。试试下面的就行了

要在 CreditCard.class 中完成更改

    @ApiModelProperty(notes = "The owner user of credit card")
    @ManyToOne
    @JoinColumn(name = "user") // Added the name attribute
    private User user;

如果您查看@JoinColumn's name attribute的源代码,他们已经明确提到了

  • 如果连接是针对元素集合,
  • 连接列名的格式为
  • 以下内容的串联:实体的名称; "_";
  • 引用的主键列的名称。

编辑

第二部分可以直接使用JPA的功能。

List<CreditCard> findByNumberContainingAndUser(String number, User user);

【讨论】:

  • 还有一个问题....当我写查询时...以下是可以的。 @Query("SELECT card FROM CreditCard card where card.number like :searchTerm and card.user=:user") List findByNumberContainingSearchTermAndUser(String searchTerm, Long user);
  • 你要问的 upsert 逻辑?
  • 这里我只是想找到现在给定用户和搜索词的所有记录
  • 这行不通,因为 User 是一个对象而不是 Long 值,我将编辑并更新解决方案的帖子
  • 非常感谢您的帮助@Avi
猜你喜欢
  • 2010-10-23
  • 1970-01-01
  • 2018-11-02
  • 2013-05-10
  • 1970-01-01
  • 2023-03-14
  • 2016-09-16
  • 1970-01-01
  • 2021-06-03
相关资源
最近更新 更多