spring - JPA 一对一映射与继承 : 2 Queries for what should be one

标签 spring hibernate spring-data-jpa jpql

我有一个一对一的关系 Media实体和 MediaAnalysis实体所在Media实体是一个抽象基类:

新闻报道实体

@Entity
@DiscriminatorValue("N")
public class NewsReport extends Media {

    @Column(name = "BODY", nullable = false)
    private String body;

    NewsReport(){}

    public NewsReport(String title, String link, String author, String body) {
        super(title, link, author);
        this.body= body;
    }

    public String getBody() {
        return body;
    }
}

媒体实体
@Entity
@Inheritance(
        strategy = InheritanceType.SINGLE_TABLE
)
@DiscriminatorColumn(name = "TYPE", length = 1, discriminatorType = DiscriminatorType.STRING)
public abstract class Media {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @Column(name = "TITLE", nullable = false)
    private String title;

    @Column(name = "LINK", length = 500, nullable = false)
    private String link;

    @Column(name = "AUTHOR", length = 45, nullable = false)
    private String author;

    @OneToOne(mappedBy = "media")
    private MediaAnalysis analysis;

    Media(){}

    public Media(String title, String link, String author) {
        this.title = title;
        this.link = link;
        this.author = author;
    }

    // getters

    public Optional<MediaAnalysis> getAnalysis() {
        return Optional.ofNullable(analysis);
    }
}

媒体分析
@Entity
public class MediaAnalysis {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @Column(name = "SUCCESS", nullable = false)
    private Boolean success;

    @OneToOne
    @JoinColumn(
            name = "MED_ID",
            nullable = false,
            foreignKey = @ForeignKey(name="MEA_MED_FK")
    )
    private Media media;

    @Column(name = "CONTENT", nullable = false)
    private String content;

    MediaAnalysis() { }

    public MediaAnalysis(Media media, Boolean success, String content) {
        this.media = media;
        this.success = success;
        this.content = content;
    }

    // getters

    public Media getMedia() {
        return media;
    }

    public String getContent() {
        return content;
    }
}

现在当我想使用我的 AnalysisRepository.getByMedia(..a NewsReport...)
public interface AnalysisRepository extends JpaRepository<MediaAnalysis,Long> {

    @Query("SELECT a FROM MediaAnalysis a LEFT JOIN FETCH a.media WHERE a.media = ?1")
    Optional<MediaAnalysis> getByMedia(Media media);

}

查找 MediaAnalysis来自 NewsReport例如,我希望 hibernate 运行单个 SELECT查询,例如:

SELECT m.* from mediaanalysis m where m.med_id = ?



但是,当我启用查询日志记录时,我看到 2:

DEBUG o.h.SQL:92 - select mediaanaly0_.id as id1_0_0_, media1_.id as id2_1_1_, mediaanaly0_.med_id as med_id3_0_0_, mediaanaly0_.success as success2_0_0_, media1_.author as author3_1_1_, media1_.link as link4_1_1_, media1_.title as title5_1_1_, media1_.body as body6_1_1_, media1_.type as type1_1_1_ from mea_media_analysis mediaanaly0_ left outer join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?

TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]

DEBUG o.h.SQL:92 - select mediaanaly0_.id as id1_0_1_, mediaanaly0_.med_id as med_id3_0_1_, mediaanaly0_.success as success2_0_1_, media1_.id as id2_1_0_, media1_.author as author3_1_0_, media1_.link as link4_1_0_, media1_.title as title5_1_0_, media1_.body as body6_1_0_, media1_.type as type1_1_0_ from mea_media_analysis mediaanaly0_ inner join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?

TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]



看来要先选MediaAnalysis正如预期的那样,但是还有一个似乎没有必要的其他查询。我能分辨出这两个查询之间的唯一区别是连接类型。我认为问题与 Media 有关遗产。

为什么会这样? + 我该怎么做才能确保这是一个查询?

进一步说明,如果我删除 @Query从我的存储库中实际上有 查询!。

DEBUG o.h.SQL:92 - select mediaanaly0_.id as id1_0_, mediaanaly0_.med_id as med_id3_0_, mediaanaly0_.success as success2_0_ from mea_media_analysis mediaanaly0_ left outer join med_media media1_ on mediaanaly0_.med_id=media1_.id where media1_.id=?

TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]

DEBUG o.h.SQL:92 - select media0_.id as id2_1_0_, media0_.author as author3_1_0_, media0_.link as link4_1_0_, media0_.title as title5_1_0_, media0_.body as body6_1_0_, media0_.type as type1_1_0_, mediaanaly1_.id as id1_0_1_, mediaanaly1_.med_id as med_id3_0_1_, mediaanaly1_.success as success2_0_1_ from med_media media0_ left outer join mea_media_analysis mediaanaly1_ on media0_.id=mediaanaly1_.med_id where media0_.id=?

TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]

DEBUG o.h.SQL:92 - select mediaanaly0_.id as id1_0_1_, mediaanaly0_.med_id as med_id3_0_1_, mediaanaly0_.success as success2_0_1_, media1_.id as id2_1_0_, media1_.author as author3_1_0_, media1_.link as link4_1_0_, media1_.title as title5_1_0_, media1_.body as body6_1_0_, media1_.type as type1_1_0_ from mea_media_analysis mediaanaly0_ inner join med_media media1_ on mediaanaly0_.med_id=media1_.id where mediaanaly0_.med_id=?

TRACE o.h.t.d.s.BasicBinder:65 - binding parameter [1] as [BIGINT] - [1]

最佳答案

我没有使用 JpaRepository 的经验,只是(很多)使用 Hibernate(主要是 CriteriaBuilder),但有一些想法:

  • 尝试映射 @OneToOne仅在两个实体之一中(根据您的示例应该是 MediaAnalysis)
  • 尝试映射 MediaAnalysis作为 1:n 关系(好像每个媒体可能有多个 MediaAnalysis,这很可能在我的理解中,只是可能不在您的域中)。

  • 看看是否有任何对生成的查询有帮助。

    关于spring - JPA 一对一映射与继承 : 2 Queries for what should be one,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48169664/

    相关文章:

    java - Spring JPA 数据存储库

    java - Spring Hibernate - 查找与另一个实体的字段匹配的实体

    java - Spring 3.2 和 Hibernate 4 - 由于 SessionFactory 为空而获取 NullPointerException

    java - Spring Data - MongoDb - 如果我更新同一文档两次会发生什么

    java - POJO 不相关或不可用时的 HQL 查询

    java - 错误 : You have an error in your SQL syntax in Hibernate

    java - Spring Integration 和 JPA 更新出站网关时出现循环引用错误

    spring - 将 SSL 根证书加载到 TrustManager 失败

    java - Spring MVC - JSON - 配置将日历解析为 Java 对象

    hibernate - 启动 Tomcat 9.0.13 时,cglib jar 总是会出现不同版本的错误