简体   繁体   中英

One to many JPA query without join clause

Given two tables (scripts for SQL Server) with a one to many relationship:

CREATE TABLE address (
  id BIGINT IDENTITY (1, 1) NOT NULL,
  street VARCHAR(255),
  zip VARCHAR(32),
  city VARCHAR(255),  
  country VARCHAR(32),

  CONSTRAINT PK_address PRIMARY KEY NONCLUSTERED(id)
);
CREATE TABLE person (
  id BIGINT IDENTITY (1, 1) NOT NULL,
  address_id BIGINT NOT NULL,
  first_name VARCHAR(32),
  last_name VARCHAR(32),

  CONSTRAINT PK_person PRIMARY KEY NONCLUSTERED(id),
  CONSTRAINT FK_person_address FOREIGN KEY (address_id) REFERENCES address
); 

A person has exactly one address, but the same address can be linked to multiple different persons.

There is also a Spring JPA repository with one explicit query:

@Repository
public interface PersonJpaRepository extends JpaRepository<Person, Long> {

    List<Person> findByAddressId(Long addressId);
}

Using Hibernate as JPA provider an SQL similar to this is generated for this find method:

select person0_.id, person0_.first_name, person0_.last_name
from person person0_ 
left outer join address address1_ on person0_.address_id=address1_.id 
where person0_.address_id=?

As I am not interessted in any data from the address table and I know the address_id allready, there seems no real need for the join:

select person0_.id, person0_.first_name, person0_.last_name
from person person0_ 
where person0_.address_id=?

This query gives the same result.

Is there anyway I can get JPA/Hibernate to produce the SQL without the join without defining the query explicitly through @Query ?

You cannot change the behavior of Hibernate but you don't have to care about the join.

The database will optimize the query anyway because there is no protection from the table address.

So from the DB side both queries are the same.

Yes you can! And I can be very helpful, to eliminate the join, because it doesn't introduce a second table name. For example, this can make an ORDER much easier because it's no necessary to name the table.

To make it more concrete. It's possible to do a HQL-SELCT and restrict a ManyToOne relationship, without any join in the resulting SQL :

Instead of using a join in

session.createQuery("FROM Person person WHERE person.adress.id = 42")

we use can use the adress_id column

session.createQuery("FROM Person person WHERE person.adressId = 42")

This works, if you specify an additional adressId field, which is only used as mapping info for Hibernate:

@Entity
@Access(AccessType.FIELD)
public class Person{
    @Id
    String id;

    @JoinColumn(name = "adress_id") 
    @ManyToOne(fetch = FetchType.LAZY)
    @Nullable
    public Adress adress;


    @Column(name = "adress_id", insertable = false, updatable = false)
    private String adressId;

 // [... street, zip, city, country]
}


@Entity
@Access(FIELD)
public class Adress{
    @Id
    String id;

   // [... firstName, lastName]
}

The AccessType.FIELD is not needed (But we can leave getters/setters in example). The FetchType.LAZY and @Nullable are also optional, but make it clear when it makes sense to use it. We are able to load Person entities which have a specific Address (we know the address id). But we don't need a join because it's not needed for the WHERE-clause and not for the initial fetch (the address can be fetched lazy).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM