Search code examples
javahibernatejpaormhibernate-mapping

JPA: Selecting subset of entity won't load @OneToOne property


I have a gigantic entity and I'd like to load its subset (ID and baz property):

@Entity
public class GiganticEntity {

    @Id Long id;

    @OneToOne(mappedBy = "giganticEntity")
    Foo foo;

    @OneToOne(mappedBy = "giganticEntity")
    Bar bar;

    @OneToOne(mappedBy = "giganticEntity")
    Baz baz;

    // default constructor + getters/setters

    public GiganticEntity(Long id, Baz baz) {
        this.id = id;
        this.baz = baz;
    }
}

I tried using following JPA query, but baz property will be null:

"SELECT new package.GiganticEntity(ge.id, ge.baz) " +
"FROM GiganticEntity ge WHERE ge.id = 1";

I tried adding an explicit join, but it resulted in null as well:

"SELECT new package.GiganticEntity(ge.id, b) FROM GiganticEntity ge " +
    "LEFT JOIN ge.baz as b " +
    "WHERE ge.id = 1";

If I only select my gigantic entity like this then everything works (but I am trying to save some joins):

"SELECT GiganticEntity g WHERE g.id = 1";

Is this achievable with JPA? I am using Hibernate as its implementation.

EDIT: Query actually needs to be LEFT JOIN, so I need all gigantic entites with baz-es.


Solution

  • Since GiganticEntity has an inverse one-to-one association to a Baz:

    @OneToOne(mappedBy = "giganticEntity")
    Baz baz;
    

    It means that Baz has also an association to GiganticEntity:

    @OneToOne
    GiganticEntity giganticEntity;
    

    The query can therefore become:

    select new package.GiganticEntity(g.id, b)  
    from Baz b
    join b.giganticEntity g
    where g.id : id
    

    Edit

    According to the question requirements changes:

    Query actually needs to be LEFT JOIN, so I need all gigantic entites with baz-es.

    You can map multiple entities to the same table. You will have the GiganticEntity containing all associations and several entity views:

    @Entity
    @Table(name="GiganticEntity")
    @Immutable
    public class GignaticBazViewEntity {
    
        @Id Long id;
    
        @OneToOne(mappedBy = "bar")
        Bar bar;
    
        @OneToOne(mappedBy = "baz")
        Baz baz;
    
        public GiganticEntity(Long id, Bar bar, Baz baz) {
            this.id = id;
            this.bar = bar;
            this.baz = baz;
        }
    }
    

    The query goes like this:

    select g
    from GignaticBazViewEntity g
    left join fetch g.bar
    left join fetch g.baz
    where g.id : id
    

    or

    select g
    from GignaticBazViewEntity g
    FETCH ALL PROPERTIES
    where g.id : id