title: Spring JPA OneToOne mapped entities not behaving properly in Transactional tests
body: <p>So I'm writing tests for some logic around some Spring JpaRepositories I have created. I'm doing this using the embedded in-memory H2 database. I'm seeing a weird scenario where my OneToOne mapped entities aren't behaving properly.</p>
  
  <p>My <code>User</code> and <code>SSOUser</code> are entities joined with a OneToOne relationship, with the <code>SSOUser</code> entity simply having additional metadata for a user that is signing in with our SSO solution. In the test code I am providing below, when <code>@Transactional</code> is NOT applied, everything works. When I do add <code>@Transactional</code>, however, it fails on the commented line:</p>
  
  <pre><code>@Test
  public void test_saveFindUserAndSsoUser() throws Exception {
      User user = mockUser();
      user = userCarrierRepository.saveAndFlush(user);
      SSOUser ssoUser = new SSOUser();
      ssoUser.setUser(user);
      ssoUser = ssoUserRepository.saveAndFlush(ssoUser);
  
      assertNotNull(user.getId());
      assertNotNull(ssoUser.getId());
      SSOUser ssoUser2 = ssoUserRepository.findById(ssoUser.getId())
              .orElseThrow(() -&gt; new Exception("Could not find SSO User by ID"));
      assertThat(ssoUser2, allOf(
              hasProperty("id", equalTo(ssoUser.getId())),
              hasProperty("user", notNullValue())
      ));
      assertThat(ssoUser2.getUser(), hasProperty("id", equalTo(user.getId())));
  
      final User user2 = userCarrierRepository.findById(user.getId())
              .orElseThrow(() -&gt; new Exception("Could not find User by ID"));
  
      assertThat(user2, allOf(
              hasProperty("id", equalTo(user.getId())),
              hasProperty("ssoUser", notNullValue()) // FAILS HERE BECAUSE ssoUser IS NULL
      ));
      assertThat(user2.getSsoUser(), hasProperty("id", equalTo(ssoUser.getId())));
  }
  </code></pre>
  
  <p>The User entity, using Lombok, is:</p>
  
  <pre><code>@Data
  @Entity
  @Table(name="user")
  public class User implements Serializable {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name="id")
      private Long id;
  
      @OneToOne(fetch = FetchType.LAZY, mappedBy = "user")
      private SSOUser ssoUser;
  
      public boolean isSSOUser() {
          return ssoUser != null;
      }
  }
  </code></pre>
  
  <p>The SSOUser entity, using Lombok, is:</p>
  
  <pre><code>@Data
  @Entity
  @Table(name = "sso_user")
  public class SSOUser implements Serializable {
  
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
  
      @OneToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "user_id")
      private User user;
  
  }
  </code></pre>
  
  <p>And here is the SQL DDL statement to add the appropriate table to our database:</p>
  
  <pre><code>CREATE TABLE sso_user (
    id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (user_id) REFERENCES public.user (id)
  );
  </code></pre>
  
  <p>So, back to the original code, the <code>User</code> entity is being saved with the <code>ssoUser</code> field as null. However, the <code>SSOUser</code> entity is being saved with a valid <code>User</code> entity. I would expect the <code>sso_user</code> table to contain the appropriate value in the <code>user_id</code> column.</p>
  
  <p>Because of the fact that the data is correct in the <code>sso_user</code> table, I would expect <code>userCarrierRepository.findById(...)</code> to return a <code>User</code> with the joined <code>ssoUser</code> included, just as I would expect <code>sslUserRepository.findById(...)</code> to return the <code>SSOUser</code> with the joined <code>user</code> included.</p>
  
  <p>However, that is not what is happening. Only the SSOUser is being returned with the joined entity, the User is not.</p>
  
  <p>Again, this only happens if I add @Transactional to the code provided here. Without that annotation, everything works as I would expect.</p>
  
  <p>I'm hoping someone can explain this for me. Thank you so much.</p>