Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA One to One mapping with inheritance: 2 Queries for what should be one

I have a one to one relationship between a Media entitiy and a MediaAnalysis entity where the Media entity is an abstract base class:

News Report Entity

@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;
    }
}

Media Entity

@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);
    }
}

Media 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;
    }
}

Now when I want to use my 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);

}

To find an MediaAnalysis by a NewsReport for example I would expect hibernate to run a single SELECT query, something like:

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

But instead when I enable query logging I see 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]

It seems to first select the MediaAnalysis as expected, but then there's one other query which seem unneccessary. The only difference I can tell between those two queries is the join type. I presume the issue is to do with the Media inheritance.

Why is this happening? + What can I do to make sure this is one query?


On a further note, if I remove the @Query from my repository there is actually three queries!.

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]

like image 875
Eduardo Avatar asked Oct 29 '22 21:10

Eduardo


1 Answers

I have no experience with JpaRepository, just (a lot) with Hibernate (& CriteriaBuilder mostly), but some ideas:

  • try to map the @OneToOne in only one of the two entities (should be MediaAnalysis per your example)
  • try to map MediaAnalysis as 1:n relation (as if it would be possible to have multiple MediaAnalysis per Media, which might well be in my understanding, just perhaps not in your domain).

See if any of that helps with the queries generated.

like image 90
Kirinya Avatar answered Nov 15 '22 11:11

Kirinya