2

I have an entity representing a MySQL table:

@Entity
@Table(name = "group_")
@Getter
@Setter
@SuppressWarnings("serial")
public class GroupEntity
        implements Serializable {

    @Id
    @GeneratedValue(generator = "uuid2")
    @Column(name = "group_id")
    private UUID groupId;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "owner_account_id")
    @NotNull
    private AccountEntity ownerAccount;

    @Column(name = "value")
    @NotBlank
    private String value;

}

And a projection:

public interface GroupBaseProjection {

    UUID getGroupId();

    AccountEntity getOwnerAccount();

}

This is my repository:

public interface GroupsRepository extends JpaRepository<GroupEntity, UUID> {

    GroupBaseProjection findBaseByGroupId(UUID groupId);

}

When I retrieve the entity, the ownerAccount is loaded lazily (the Hibernate MySQL query only selects its ID) but when I retrieve the projection, it is loaded eagerly (the Hibernate MySQL query does an inner join with all the AccountEntity columns). So there is no way I can retrieve only some columns of the GroupEntity (I have to retrieve all of them using the entity, or some of them plus all the columns of the AccountEntity using the projection).

Is there a way I can get the projection to load the @ManyToOne relation lazily? I've tried annotating the getOwnerAccount() method of projection with @ManyToOne(fetch = FetchType.LAZY, optional = false) and @LazyToOne(LazyToOneOption.PROXY) but it did not work.

  • You shouldn't use projection that contain Entities. Instead you should just select the columns you need – Simon Martinelli Mar 18 '21 at 12:36
  • I can do that but (1) it won't make a difference since nested projections select all columns, not just the defined ones in the getters, and (2) I don't want to get some columns from the account table, I just want the id (I don't want to see the inner join even if it is with just the id column) – s3curitybug Mar 18 '21 at 13:29

1 Answers1

0

So there is no way I can retrieve only some columns of the GroupEntity

Sure there is, just use a nested projection:

public interface AccountProjection {

    Long getId();

    String getName();

   ... // other columns

} 

public interface GroupBaseProjection {

    UUID getGroupId();

    AccountProjection getOwnerAccount();

}

Is there a way I can get the projection to load the @ManyToOne relation lazily?

I wouldn't think so, since projections are not entities, and so they are not managed by JPA.

EDIT It would seem nested projections select all the entity properties anyway (see comments). As a workaround, if you're only interested in the id, you could try mapping the join column once again as a simple property:

@Column(name = "owner_account_id", insertable = false, updatable = false)
private Long ownerAccountId;

this way, you'll be able to make it part of the projection.

crizzis
  • 9,978
  • 2
  • 28
  • 47
  • 1
    Nested projections retrive all columns, even if they have only some of them defined in the getters: https://stackoverflow.com/questions/47159647/spring-jpa-nested-projection-generating-incorrect-query https://github.com/spring-projects/spring-data-jpa/issues/1555 (I also tried it) – s3curitybug Mar 18 '21 at 13:19
  • @s3curitybug Oops, didn't realize that. See my updated answer for a possible workaround – crizzis Mar 18 '21 at 15:19
  • That's a possibility, but it feels like a dirty hack. – s3curitybug Mar 18 '21 at 15:44