DataJpaTest using H2 not able to access data in Subselect Entity
Asked Answered
T

1

8

I am running a unit test set up as a DataJpaTest with an H2 database. It worked well, until I introduced a new Immutable Entity set using a Subselect. It does not break, but it does not find data that it should. I see in the SQL that it is correctly joining to the Subselect query.

When running as normal as an application, the @Subselect entity works fine, so it is an issue with the unit test setup somehow.

Here is my Main entity:

@Entity
@DynamicUpdate
@Getter
@Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@Table(name = "apps", schema = "public")
public class App extends BaseEntity
{
    @Id
    @Column(name = "app_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ent_generator")
    @SequenceGenerator(name = "ent_generator", sequenceName = "entity_seq", allocationSize = 1)
    private long appId;

    @EqualsAndHashCode.Include
    @Basic
    @Column(name = "app_name", length = 200)
    private String appCode;

    @EqualsAndHashCode.Include
    @Basic
    @Column(name = "app_ver_name", length = 200)
    private String appVersion;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_app_id")
    private App parent;

    // ...

    @OneToMany(
            mappedBy = "app",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private Set<TrainingRequirement> trainingRequirements = new HashSet<>();

    @OneToMany(mappedBy = "app")
    private Set<EffectiveTrainingRequirement> effectiveTrainingRequirements = new HashSet<>();

   // ...
}

Here is my @Subselect entity:

@Entity
@Immutable
@Subselect(
        "SELECT\n" +
        "     tr.trn_req_id AS trn_req_id\n" +
        "   , tr.app_id AS app_id\n" +
        "   FROM apps a\n" +
        "   JOIN training_reqs tr\n" +
        "-- ...")
@Synchronize({"apps","training_reqs"})
public class EffectiveTrainingRequirement
{
    @Id
    @Column(name = "trn_req_id", nullable = false)
    private long trainingRequirementId;

    @EqualsAndHashCode.Include
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "app_id")
    private App app;    
}

Here is the Unit test code (vastly reduced for relevant parts):

@RunWith(SpringRunner.class)
@DataJpaTest
public class TrainingRequirementRepositoryTest
{
    @Autowired
    private TestEntityManager entityManager;
    @Autowired
    private AppRepository appRepository;

    @Before
    public void setup()
    {
        // ...
        app4 = new App(organization, "a4");
        app4.addTrainingRequirement(new TrainingRequirement("treq6", c6));
        app4.addTrainingRequirement(new TrainingRequirement("treq7", c7, tr1));
        app4.addTrainingRequirement(new TrainingRequirement("treq8", c8, tr2));
        entityManager.persist(app4);

        app4v2 = new App(organization, "a4", app4, "v2");
        app4v2.setParent(app4);
        app4v2.addTrainingRequirement(treq7chg = new TrainingRequirement("treq7", c7, tr2));
        treq7chg.setChangeType(InheritOverride.CHANGE);
        app4v2.addTrainingRequirement(treq6rmv = new TrainingRequirement("treq6"));
        treq6rmv.setChangeType(InheritOverride.REMOVE);
        app4v2.addTrainingRequirement(treq9add = new TrainingRequirement("treq9", c9, tr4));
        treq9add.setChangeType(InheritOverride.ADDITION);
        entityManager.persist(app4v2);
    }

    @Test
    public void test_AppWithEffectiveTR()
    {
        App app = appRepository.getAppWithParent(organization, "a4", "v2").get();

        logger.debug("# tr: "+app.getTrainingRequirements().size());
        logger.debug("# etr: "+app.getEffectiveTrainingRequirements().size());
        for (EffectiveTrainingRequirement tr : app.getEffectiveTrainingRequirements())
            logger.debug("tr: "+tr.toString());
    }

}

The repository:

@Repository
public interface AppRepository extends CrudRepository<App, Long>
{
    String APP_FETCH_QUERY = "SELECT a FROM App a " +
                             "LEFT JOIN FETCH a.parent p " +
                             "LEFT JOIN FETCH a.trainingRequirements atr " +
                             "LEFT JOIN FETCH a.effectiveTrainingRequirements ";

    @Query(value = APP_FETCH_QUERY +
                   "WHERE a.organization = :org " +
                   " AND a.appCode = :appCode " +
                   " AND a.appVersion = :appVersion" )
    Optional<App> getAppWithParent(@Param("org") Organization org,
                                   @Param("appCode") String appCode,
                                   @Param("appVersion") String appVersion);
}
Toile answered 20/9, 2020 at 21:18 Comment(0)
A
0

I think you cannot use @Subselect entity with inmemory database. Database structure is missing to process your native query in subselect.

Arsine answered 9/2 at 6:32 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Avignon

© 2022 - 2024 — McMap. All rights reserved.