Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate FetchMode.JOIN ignored in Embeddable used as ID

I have the following entity structure (the DB is given):

@Data
@Entity
public class Report {
    
   @EmbeddedId
   private ReportId id;
    
   private int numberOne;
    
   private int numberTwo;
}

Within my reports I need the complete site. But it might be deleted (no foreign key constraint).

@Data
@Entity
public class Site {
    
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;
    
   private String place;
    
   private String name;
}

For every site and day there is a report. I am not interested in reports from deleted sites.

@Embeddable
@Data
public class ReportId implements Serializable {
    
   @NotFound(action = NotFoundAction.IGNORE) //without this we get EntityNotFoundException for deleted sites
   @Fetch(FetchMode.JOIN)
   @OneToOne
   @JoinColumn(name = "site_id", referencedColumnName = "id")
   private Site site;
    
   @Column(name = "day")
   private LocalDate date;
}

What I want is that a "selectAll()" only returns reports that are linked to existing sites (lookup by site id is returning not null). As you see I already tried @NotFound(action = NotFoundAction.IGNORE) but this creates entries with site = null.

I think what I need is a left outer join of site but it seems @Fetch(FetchMode.JOIN) is just ignored - I still see 2 selects per report (first selecting the report 2nd fetching the site by id).

I also tried to put these annotations on to @EmbeddedId column in Report but this is not working (@NotFound is also ignored there).

Is there a way to ignore all reports without an existing site? - I don't want to write the queries manually. I want to use Spring Data repository methods like - findAll().

like image 736
dermoritz Avatar asked Nov 20 '25 20:11

dermoritz


2 Answers

Actually under the hood when you run the findAll() method spring data jpa perform the following jpa query:

select r from Report r

But as it stated in the hibernate documentation:

The reason why we are not using a JPQL query to fetch multiple entities is because the FetchMode.JOIN strategy would be overridden by the query fetching directive.

To fetch multiple relationships with a JPQL query, the JOIN FETCH directive must be used instead.

Therefore, FetchMode.JOIN is useful for when entities are fetched directly, via their identifier or natural-id.

Also, the FetchMode.JOIN acts as a FetchType.EAGER strategy. Even if we mark the association as FetchType.LAZY, the FetchMode.JOIN will load the association eagerly.

So, it looks like you will not be able to achieve that you want without a separate query.

like image 87
SternK Avatar answered Nov 23 '25 15:11

SternK


This is a known Hibernate issue. Just don't define associations in the embedded id type. You can define the basic column attributes in the embedded id type and the associations in the main entity type by using @JoinColumn(insertable = false, updatable = false)

UPDATE: Use this:

@Embeddable
@Data
public class ReportId implements Serializable {
   
   @Column(name = "site_id", referencedColumnName = "id")
   private Integer siteId;
    
   @Column(name = "day")
   private LocalDate date;
}

@Data
@Entity
public class Report {
    
   @EmbeddedId
   private ReportId id;
   
   @Fetch(FetchMode.JOIN)
   @OneToOne
   @Column(name = "site_id", referencedColumnName = "id", insertable = false, updatable = false)
   private Site site;

   private int numberOne;
    
   private int numberTwo;
}

I can't find the issue right now, you can open a new one if you want.

like image 29
Christian Beikov Avatar answered Nov 23 '25 14:11

Christian Beikov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!