【问题标题】:"Could not prepare statement" OneToMany“无法准备声明”OneToMany
【发布时间】:2022-01-02 16:55:39
【问题描述】:

这是我想要达到的目标:

编写一个提供存储库详细信息的 Web 服务:id、名称、用户名和 提交列表。

????需要以JSON格式返回,例如:

{
  "repository_id": "1",
  "repository_name": "My repo",
  "owner": "Noah",
  "commits": [
    "First commit",
    "Second commit",
    "Third commit"
  ]
}

您将在下面找到数据库结构:

这是我的CrudRepository,其中包含我正在尝试构建的查询:

public interface RepositoriesDB extends CrudRepository<Repository, String> {
    @Query(value = "SELECT r.repositoryId, r.repositoryName, r.owner.userName, r.commits FROM Repository r WHERE r.repositoryId = :repoId")
    List<Object[]> getRepo(@Param("repoId") long repoId);
}

我的User 班级:

@Entity
@NoArgsConstructor
@Data
public class User {
    @NotNull
    @Id
    private String userLogin;

    @NotBlank
    @NotNull
    private String userName;

    @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JsonIgnore
    private List<Repository> repositories;
}

我的Repository 班级:

@Entity
@NoArgsConstructor
@Data
public class Repository {
    @NotNull
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long repositoryId;

    @NotNull
    @NotBlank
    @Size(min = 3, max = 25)
    private String repositoryName;

    @OneToMany(mappedBy = "repository", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JsonIgnore
    private List<Commit> commits;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "owner_login", nullable = false)
    private User owner;
}

我的Commit 班级:

@Entity
@NoArgsConstructor
@Data
public class Commit {
    @NotNull
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long commitId;

    @NotBlank
    @NotNull
    private LocalDateTime date = LocalDateTime.now();

    @NotNull
    @NotBlank
    @Size(min = 1, max = 255)
    private String message;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "repository_id", nullable = false)
    private Repository repository;
}

最后,这里是堆栈跟踪:

There was an unexpected error (type=Internal Server Error, status=500).
could not prepare statement; SQL [select repository0_.repository_id as col_0_0_, repository0_.repository_name as col_1_0_, user1_.user_name as col_2_0_, . as col_3_0_, commits2_.commit_id as commit_i1_0_, commits2_.date as date2_0_, commits2_.message as message3_0_, commits2_.repository_id as reposito4_0_ from repository repository0_ cross join user user1_ inner join commit commits2_ on repository0_.repository_id=commits2_.repository_id where repository0_.owner_login=user1_.user_login and repository0_.repository_id=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select repository0_.repository_id as col_0_0_, repository0_.repository_name as col_1_0_, user1_.user_name as col_2_0_, . as col_3_0_, commits2_.commit_id as commit_i1_0_, commits2_.date as date2_0_, commits2_.message as message3_0_, commits2_.repository_id as reposito4_0_ from repository repository0_ cross join user user1_ inner join commit commits2_ on repository0_.repository_id=commits2_.repository_id where repository0_.owner_login=user1_.user_login and repository0_.repository_id=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
[...]
Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
[...]
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "SELECT REPOSITORY0_.REPOSITORY_ID AS COL_0_0_, REPOSITORY0_.REPOSITORY_NAME AS COL_1_0_, USER1_.USER_NAME AS COL_2_0_, .[*] AS COL_3_0_, COMMITS2_.COMMIT_ID AS COMMIT_I1_0_, COMMITS2_.DATE AS DATE2_0_, COMMITS2_.MESSAGE AS MESSAGE3_0_, COMMITS2_.REPOSITORY_ID AS REPOSITO4_0_ FROM REPOSITORY REPOSITORY0_ CROSS JOIN USER USER1_ INNER JOIN COMMIT COMMITS2_ ON REPOSITORY0_.REPOSITORY_ID=COMMITS2_.REPOSITORY_ID WHERE REPOSITORY0_.OWNER_LOGIN=USER1_.USER_LOGIN AND REPOSITORY0_.REPOSITORY_ID=?"; expected "*, NOT, EXISTS, INTERSECTS, UNIQUE"; SQL statement:
select repository0_.repository_id as col_0_0_, repository0_.repository_name as col_1_0_, user1_.user_name as col_2_0_, . as col_3_0_, commits2_.commit_id as commit_i1_0_, commits2_.date as date2_0_, commits2_.message as message3_0_, commits2_.repository_id as reposito4_0_ from repository repository0_ cross join user user1_ inner join commit commits2_ on repository0_.repository_id=commits2_.repository_id where repository0_.owner_login=user1_.user_login and repository0_.repository_id=? [42001-200]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:453)
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
    at org.h2.message.DbException.getSyntaxError(DbException.java:243)
    at org.h2.command.Parser.getSyntaxError(Parser.java:1053)
[...]

我相信问题出在我试图选择 OneToMany 关系这一事实,因为我在选择所有者时没有这个问题,因为我有一个 @JsonIgnore 注释和无限循环......
除了,在这种情况下,我需要选择交易列表:(

提前感谢您的帮助!

【问题讨论】:

  • 你试过WHERE r.repositoryId = ?1而不是WHERE r.repositoryId = :repoId吗?
  • 是的,我已经有了:/ 也不起作用
  • r.owner.userName 和 r.commits 之间缺少逗号?
  • @Alien 在我复制/粘贴时只是一个错字,我的错。我的代码中有逗号,所以也不是问题:/
  • 我认为你必须更改public interface RepositoriesDB extends CrudRepository&lt;Repository, Long&gt;,因为Repository 有一个Long id 类型而不是String 一个

标签: spring spring-boot jpa spring-repositories


【解决方案1】:

您的 sql 查询中的错误是 r.commits 部分。它是一个值列表,sql 列只接受 single (or scalar) 值类型,如 numbervarchar

由于RepositoryCommit 实体之间的关系是One-To-Many 关联,所以r.commits 是一个值列表,因此Hibernate 无法准备sql 语句。

您可以从 sql 查询中删除 r.commits 部分,它会起作用。

如果您想获取存储库的提交列表,您可以为此实现一个特定的方法。 类似的东西

public interface CommitRepository extends JpaRepository<Commit, Long> {
      List<Commit> findAllByRepository(Repository repository);
}

您可以将要获取所有关联提交的repository 对象传递给此方法。

另外,由于Repository.repositoryIdLong 数据类型,因此您必须将RepositoriesDB 定义更改为

public interface RepositoriesDB extends JpaRepository<Repository, Long>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 2019-08-04
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多