Java JPA/Hibernate在OneToOne Find上双击

Java JPA/Hibernate在OneToOne Find上双击,java,hibernate,jpa,Java,Hibernate,Jpa,在学习JPA/Hibernate时,我偶然发现了一些意想不到的事情。我得到了一个不必要的对数据库的双击查询(见按钮)。我有一个简单的OneTONE设置 这是我的联系人实体: @Entity @Table(name = "contact") public class Contact { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "contact_id", nullable = fals

在学习JPA/Hibernate时,我偶然发现了一些意想不到的事情。我得到了一个不必要的对数据库的双击查询(见按钮)。我有一个简单的OneTONE设置

这是我的联系人实体:

@Entity
@Table(name = "contact")
public class Contact {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "contact_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @OneToOne
  @JoinColumn(name="fk_address_id", referencedColumnName="address_id")
  private Address address;

  public Contact(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  // getters/setters

}
@Entity
@Table(name = "address")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "address_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "location", nullable = false)
  private String location;

  @OneToOne(mappedBy = "address")
  private Contact contact;

  public Address(String location) {
    this.location = location;
  }

  // getters/setters

}
我的地址实体:

@Entity
@Table(name = "contact")
public class Contact {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "contact_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @OneToOne
  @JoinColumn(name="fk_address_id", referencedColumnName="address_id")
  private Address address;

  public Contact(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  // getters/setters

}
@Entity
@Table(name = "address")
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "address_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "location", nullable = false)
  private String location;

  @OneToOne(mappedBy = "address")
  private Contact contact;

  public Address(String location) {
    this.location = location;
  }

  // getters/setters

}
这是我运行代码的方式:

  private EntityManager em;

  @Before
  public void setup() {
    em = EntityManagerFactoryCreator.getEntityManagerFactory().createEntityManager();
  }

  @Test
  public void createContactWithAddress() {
    Address address = new Address("Made");
    Contact contact = new Contact("Jan", address);

    em.getTransaction().begin();
    em.persist(address);
    em.persist(contact);
    em.getTransaction().commit();

    em.close();
    em = EntityManagerFactoryCreator.getEntityManagerFactory().createEntityManager();

    Contact managedContact = em.find(Contact.class, 1L);
  }

}
这可能是愚蠢的,但是是什么导致了双重选择呢

Hibernate: 

    drop table address if exists
Hibernate: 

    drop table book if exists
Hibernate: 

    drop table contact if exists
Hibernate: 

    create table address (
       address_id bigint generated by default as identity,
        location varchar(255) not null,
        primary key (address_id)
    )
Hibernate: 

    create table book (
       book_id bigint generated by default as identity,
        category varchar(255),
        release_date date,
        summary varchar(255),
        title varchar(255) not null,
        primary key (book_id)
    )

Hibernate: 

    create table contact (
       contact_id bigint generated by default as identity,
        name varchar(255) not null,
        address_address_id bigint,
        primary key (contact_id)
    )
Hibernate: 

    alter table book 
       add constraint UK_g0286ag1dlt4473st1ugemd0m unique (title)
Hibernate: 

    alter table contact 
       add constraint FKrc0ixa9b11b9tv3hyq0iwvdpt 
       foreign key (address_address_id) 
       references address
Hibernate: 
    insert 
    into
        address
        (address_id, location) 
    values
        (null, ?)
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [VARCHAR] - [Made]
Hibernate: 
    insert 
    into
        contact
        (contact_id, address_address_id, name) 
    values
        (null, ?, ?)
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [2] as [VARCHAR] - [Jan]
Hibernate: 
    select
        contact0_.contact_id as contact_1_2_0_,
        contact0_.address_address_id as address_3_2_0_,
        contact0_.name as name2_2_0_,
        address1_.address_id as address_1_0_1_,
        address1_.location as location2_0_1_ 
    from
        contact contact0_ 
    left outer join
        address address1_ 
            on contact0_.address_address_id=address1_.address_id 
    where
        contact0_.contact_id=?
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_1_0_1_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_3_2_0_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([name2_2_0_] : [VARCHAR]) - [Jan]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([location2_0_1_] : [VARCHAR]) - [Made]
Hibernate: 
    select
        contact0_.contact_id as contact_1_2_1_,
        contact0_.address_address_id as address_3_2_1_,
        contact0_.name as name2_2_1_,
        address1_.address_id as address_1_0_0_,
        address1_.location as location2_0_0_ 
    from
        contact contact0_ 
    left outer join
        address address1_ 
            on contact0_.address_address_id=address1_.address_id 
    where
        contact0_.address_address_id=?
TRACE o.h.t.d.s.BasicBinder [main]: binding parameter [1] as [BIGINT] - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([address_1_0_0_] : [BIGINT]) - [1]
TRACE o.h.t.d.s.BasicExtractor [main]: extracted value ([contact_1_2_1_] : [BIGINT]) - [1]
注: 我的EntityManagerFactoryCreator是一个调用
Persistence.createEntityManagerFactory(“nl.infosupport.javaminor.week4.jpa.h2”)


org.hibernate.jpa.HibernatePersistenceProvider

在这种情况下,这是正常的行为,对于您拥有的表配置。如果只希望有一个select,则需要使用自定义查询连接子表。例如,使用HQL时,它将如下所示:

    public Contact find(Long id) {
        TypedQuery<Contact> query = em.createQuery(
        "SELECT c FROM Contact c join fetch c.address WHERE c.id = :id", Contact.class);
         return query
           .setParameter("id", id)
           .getSingleResult();
    }

.

你知道我为什么不在这个代码上进行双重选择吗:
Address managedAddress=em.find(Address.class,1L);System.out.println(managedAddress.getContact())@YoshuaNahar,因为此处的地址不是父地址,它可能无法获取字段。执行初始化字段的
managedAddress.getContact()
时,您必须获得下一个查询。OneToOne很难被Hibernate处理,试着搜索它,你会发现很多奇怪行为的例子。这就是我添加它的原因,可以肯定。OneToOne在默认情况下也很热心。@YoshuaNahar更新了答案,请查看。我仍然得到2个选择。仅当我运行
em.find(Contact.class,1L)时,我才得到2个选择而不是在
em.find(Address.class,1L)上