【问题标题】:How to depict joins with @Query annotation in Spring JPA Repository method如何在 Spring JPA Repository 方法中使用 @Query 注释描述连接
【发布时间】:2019-05-12 23:09:56
【问题描述】:

我正在使用带有 JPA 和 MySQL 后端的 Spring-Boot。现在我对 Spring-Boot 提供的存储库感到很困惑。我知道这些功能非常强大(并且似乎非常有用,因为它们可以大大缩短您的代码)。尽管如此,我还是不明白如何在其中表示联接,因为结果集应该是几个实体的选择中指定属性的组合。

现在假设我们有三个表BookAuthorAuthorOfBook,其中最后一个表只是通过组合主键连接BookAuthor。我猜我们有以下 Java 类:

实体书:

@Entity
@Table(name="BOOK")
public class Book {

  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private int id;
  @Column(name = "TITLE")
  private String title;

}

实体作者

@Entity
@Table(name="AUTHOR")
public class Author {

  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private int id;
  @Column(name = "LASTNAME")
  private String lastname;
  @Column(name = "FIRSTNAME")
  private String firstname;
  //Let's assume some getters and setters and a constructor
}

实体 AuthorOfBook:

@Entity
@Table(name="BOOK")
public class Book {
  @EmbeddedId
  private AuthorOfBookId pk;
}

嵌入式 ID

@Embeddable
public class AuthorOfBookId implements Serializable {
  private int authorId;
  private int bookId;
}

存储库

@Repository
public interface AuthorOfBookRepository extends JpaRepository<,AuthorOfBookId> {

}

现在我将如何表示该查询:

SELECT b.name, a.firstname, a.lastname from AuthorOfBook ab inner join Book b on b.id = ab.book_id inner join Author a on a.id = ab.author_id where a.lastname = :lastname;

在我的存储库中?我知道签名需要像

@Query([the query string from above])
public (...) findAuthorAndBookByAuthorLastname(@Param("lastname") String lastname);

但我无法确定返回的类型。该方法返回什么? (我猜AuthorOfBook 是行不通的)

【问题讨论】:

标签: java spring spring-data-jpa


【解决方案1】:

如果你想处理审计字段,你可以这样做:

审计类

@Embeddable
public class Audit {

    @Column(name = "created_on")
    private Timestamp createdOn;

    @Column(name = "updated_on")
    private Timestamp updatedOn;

    @Column(name = "is_deleted")
    private Boolean isDeleted;

    //getters and setters

    }

AuditListener 自动更新审计字段

public class AuditListener {

    private Long loggedUser = 1001L;

    /**
     * Method to set the fields createdOn, and isDeleted when an entity is persisted
     * @param auditable
     */
    @PrePersist
    public void setCreatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();

        if (audit == null) {
            audit = new Audit();
            auditable.setAudit(audit);
        }

        audit.setIsDeleted(Boolean.FALSE);
        audit.setCreatedOn(Timestamp.from(Instant.now()));
    }

    /**
     * Method to set the fields updatedOn and updatedBy when an entity is updated
     * @param auditable
     */
    @PreUpdate
    public void setUpdatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();
        audit.setUpdatedOn(Timestamp.from(Instant.now()));
    }
}

并将其添加到实体中

@EntityListeners(AuditListener.class)
public class Book implements Auditable {

    @Embedded
    private Audit audit;

【讨论】:

    【解决方案2】:

    您不希望 AuthorOfBook 作为单独的实体。 Book 应该有一个 Author 类型的字段作为 @ManyToOne 关系。这样,给定任何Book,您都可以找到作者的详细信息。

    【讨论】:

    • 感谢您的回答。因此,即使在我的实体表示中,我也想将实体与关系联系起来,而不仅仅是表示数据库结构?我对此有以下疑问:假设我的关系数据库中有其他信息(如created-timestamp) - 我会选择相同的结构并让 JPA 处理吗?以及如何处理其中的第三个 ID?所以我有BookIdAuthorIdCustomerId
    • 还有一件事:这对我来说意味着我永远不想在我的@Entity 中有 ForeignKeys?所以每次我引用 Foreign-Key-Constraint 时,我都会直接引用那个其他实体?
    • 是的,关系应该显示在您的实体中。这代表了您的数据库结构,因为通常您的数据库中会有外键约束,而连接(@OneToOne、@OneToMany 或 @ManyToMany)代表这些外键关系。 created 时间戳通常表示创建实体(例如 Book)的时间。 BookAuthor 之间的关系将同时创建。 Customer 将再次成为一个单独的实体,并且将是一个 @ManyToMany 关系。如果您对此不清楚,请提出一个新问题。
    • 您的实体中可能有ForeignKeys。它们用于生成模式。
    • 感谢您的努力 :) 正如建议的那样,我尝试通过 3 个连接的表来实现它并打开一个新问题,因为我遇到了问题(可以找到 here。你也可以看看那个,我做错了什么?:)
    猜你喜欢
    • 2020-11-28
    • 2015-04-30
    • 2022-01-19
    • 2014-08-31
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多