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]
I have no experience with JpaRepository, just (a lot) with Hibernate (& CriteriaBuilder mostly), but some ideas:
@OneToOne
in only one of the two entities (should be MediaAnalysis per your example)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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With