【问题标题】:Problem with querying entities with a set of entities in Spring Boot @Query在 Spring Boot @Query 中使用一组实体查询实体的问题
【发布时间】:2020-11-21 20:55:34
【问题描述】:

我想在 JpaRepository 中有一个 Spring Boot @Query,它返回带有一组其他实体的实体。我知道我可以使用findAll() 方法,然后只取那些我感兴趣的行,但我认为这要慢得多。问题是我的实体Booster 包含其他实体SetBoost,当我尝试查询它时,出现错误。所以,这是我的Query

    @Query( "select new app.model.Booster(" +
            "   B.id, " +
            "   B.active, " +
            "   B.games, " +
            "   B.ownerAccount, " +
            "   B.boosts, " +
            "   B.boosterNickname, " +
            "   B.additionalInformation) " +
            "from " +
            "   Booster B " +
            "   left join Boost Bo on B.id = Bo.boostingAccount.id " +
            "where " +
            "   B.games like %?1% " +
            "   and Bo.finished = true " +
            "group by " +
            "   B.id")
    List<Booster> findBoostersForOverview(String game);

这些是我的实体类:

@Data
@Entity(name = "Booster")
public class Booster {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private boolean active;
    private String games;
    @OneToOne(mappedBy = "boosterAccount", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Account ownerAccount;
    @OneToMany(mappedBy = "boostingAccount", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Boost> boosts;
    private String boosterNickname;
    private String additionalInformation;
@Data
@Entity(name = "Boost")
public class Boost {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id",nullable=false,unique=true)
    private long id;
    private Date dateCreated;
    private Date dateFinished;
    private Date dateLastModification;
    private boolean finished;
    private boolean paused;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "boosted_account_id", referencedColumnName = "id")
    private Account boostedAccount;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "boosting_account_id", referencedColumnName = "id")
    private Booster boostingAccount;
    @OneToMany(mappedBy = "boost", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Game> games;
    private String game;
    private String additionalInformation;
    private String server;

这是控制台显示的内容:

Hibernate: 
    select
        booster0_.id as col_0_0_,
        booster0_.active as col_1_0_,
        booster0_.games as col_2_0_,
        booster0_.id as col_3_0_,
        . as col_4_0_,
        booster0_.booster_nickname as col_5_0_,
        booster0_.additional_information as col_6_0_ 
    from
        booster booster0_ 
    //HERE IS SOME MORE LOGS THAT ARE UNNECESSARY HERE

这是我得到的错误:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '. as col_4_0_, booster0_.booster_nickname as col_5_0_, booster0_.additional_info' at line 1

我知道我可以在没有SetBoost 的情况下进行查询,然后在另一个查询中获取特定的Boosts,但是在我的应用程序中会有很多SQL,我的代码会变成意大利面条。有没有简单的方法可以解决我的问题?

【问题讨论】:

  • BoosterBoost 实体是否相关?如果是这样,您可以将Boost 实体类添加到您的问题中吗?正在保存的 app.model.BoosterBooster 类之间有区别吗?
  • @KavithakaranKanapathippillai 我在代码中添加了实体类。我不明白您所说的“app.model.Booster 类和正在保存的 Booster 之间有区别吗?”,但是没有其他类 Booster,taht app.model.Booster。

标签: java sql spring-boot spring-data-jpa


【解决方案1】:

您能否将以下内容添加到您的存储库中没有任何@Query 注释并查看?

    List<Booster> findByGamesLikeAndBoostsFinishedIsTrue(String game);

【讨论】:

  • 我完全忘记了,JPA 中的查询可以通过这种方式创建。它可以工作,但不是我想要的工作方式。它多次返回相同的助推器,因为助推器有一组助推器,每次它找到一个已完成并属于给定助推器的助推器时,它都会返回它。有没有办法返回一个只有完成 Boost 的 Booster,或者我必须在 BoostserService 中做很多事情?
  • 以上查询是针对return any Booster where at least one of its boost is finished的。您的要求不同吗?如果是,是 1) return any Booster where all of its boost is finished? 2) return any Booster where at least one of its boost is finished but when returning that booster remove any other unfinished boosts from it children
  • 我想得到的查询是return any Booster for a given game with all it's finished Boost
  • 所以如果给定游戏的助推器有一些未完成的助推器,您不希望它们包含在booster.getBoosts()中吗?
  • 对于这个特定的查询 - 是的。我想知道,如果我得到了整个SetBoost 结果,然后删除未完成的一个,或者是否有办法通过查询来做到这一点。
【解决方案2】:

这里的问题,你正在使用GROUP BY。当您使用Group By 时,您可以使用聚合函数(COUNT, MAX, MIN, SUM, AVG) 将结果集按选择列中的一列或多列分组。使用 GROUP BY 函数时,聚合函数是强制

在您的情况下,我希望 Group By 不是必需的。修改您的代码,如下所示。

@Query( "select new app.model.Booster(" +
        "   B.id, " +
        "   B.active, " +
        "   B.games, " +
        "   B.ownerAccount, " +
        "   B.boosts, " +
        "   B.boosterNickname, " +
        "   B.additionalInformation) " +
        "from " +
        "   Booster B " +
        "   left join Boost Bo on B.id = Bo.boostingAccount.id " +
        "where " +
        "   B.games like %?1% " +
        "   and Bo.finished = true")
List<Booster> findBoostersForOverview(String game);

【讨论】:

  • 使用 GROUP BY 时,聚合函数不是强制性的。 SELECT a, b, c FROM some_table GROUP BY a, b, c;是从 some_table 中获取 a、b 和 c 的所有唯一组合的一种完全正常的方式。
  • 啊,你是对的。从以前的版本更改此查询后,忘记删除此行。问题是,即使我对代码应用了更改,仍然会出现错误。
  • 糟糕!无论如何,你有一个解决方案!我很高兴兄弟。
猜你喜欢
  • 2015-09-11
  • 1970-01-01
  • 2022-01-17
  • 2023-03-28
  • 2011-03-19
  • 2017-04-30
  • 2020-07-04
  • 2017-12-07
  • 2021-03-17
相关资源
最近更新 更多