Весенние данные — запрос по результату примера, отличному от результата JPQL

#java #spring #spring-data-jpa

#java #spring #spring-data-jpa

Вопрос:

Во время модульного теста я обнаружил небольшое «странное поведение» в примере запроса.

У меня есть следующее определение сущности (модель сущности Keycloak).

второй список результатов инвертирован, обычно я не использую примеры для вложенных атрибутов, но поскольку это сработало, это просто странно. что список примеров не совпадает с запросом. также я упоминаю, что для меня это не проблема … я просто попытался упростить общение с БД с помощью Example.of…

 public class RoleEntity {
    @Id
    @Column(name="ID", length = 36)
    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
    private String id;

    @Nationalized
    @Column(name = "NAME")
    private String name;
    @Nationalized
    @Column(name = "DESCRIPTION")
    private String description;

    // hax! couldn't get constraint to work properly
    @Column(name = "REALM_ID")
    private String realmId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "REALM")
    private RealmEntity realm;

    @Column(name="CLIENT_ROLE")
    private boolean clientRole;

    @Column(name="CLIENT")
    private String clientId;

    // Hack to ensure that either name client or name realm are unique. Needed due to MS-SQL as it don't allow multiple NULL values in the column, which is part of constraint
    @Column(name="CLIENT_REALM_CONSTRAINT", length = 36)
    private String clientRealmConstraint;

    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
    @JoinTable(name = "COMPOSITE_ROLE", joinColumns = @JoinColumn(name = "COMPOSITE"), inverseJoinColumns =   @JoinColumn(name = "CHILD_ROLE"))
    private Set<RoleEntity> compositeRoles;

    @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="role")
    @Fetch(FetchMode.SELECT)
    @BatchSize(size = 20)
    protected Collection<RoleAttributeEntity> attributes;
}

 @Table(name = "ROLE_ATTRIBUTE")
@Entity
public class RoleAttributeEntity {

    @Id
    @Column(name = "ID", length = 36)
    @Access(AccessType.PROPERTY)
    protected String id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ROLE_ID")
    protected RoleEntity role;

    @Column(name = "NAME")
    protected String name;

    @Nationalized
    @Column(name = "VALUE")
    protected String value;
}

@Repository
public interface RoleEntityRepository extends JpaRepository<RoleEntity, String> {
    
    @Query(value = "select r from RoleEntity r inner join r.attributes ra where ra.name = 'action'")
    List<RoleEntity> getSysmatActionRoles();
    
}


I executed this unit test as bellow. 

@Test
    void assertQueryResultRoleAttributeEntity() {
        RoleEntity roleEntitySample = new RoleEntity();
        RoleAttributeEntity rae = new RoleAttributeEntity();
        rae.setName("action");
        roleEntitySample.getAttributes().add(rae);
        Example<RoleEntity> exampleRole = Example.of(roleEntitySample);
        List<RoleEntity> lr1 = roleEntityRepository.findAll(exampleRole);
        List<RoleEntity> lr = roleEntityRepository.getSysmatActionRoles();
        assertNotNull(lr);
        assertTrue(lr.size() > 0);
        lr
        .stream()
        .forEach(r -> {
            System.err.println(r.getName());
        });
        //utializando example resultado incorreto.
        assertNotNull(lr1);
        assertTrue(lr1.size() > 0);
        lr1
        .stream()
        .forEach(r -> {
            System.err.println(r.getName());
        });
        
    }
 

Просто расширил модульный тест, чтобы определить проблему.
Пример Spring Data не проверяет отложенные коллекции (рассматриваемый атрибут).
Второй модульный тест приведен ниже.
Проблема решена с использованием RoleAttributeEntity в примере

 @Test 
void assertQueryResultRoleAttributeEntity() {
    RoleAttributeEntity rae = new RoleAttributeEntity(); 
    rae.setName(SYSMAT_ACTION_NAME);
    Example<RoleAttributeEntity> ex = Example.of(rae);
    List<RoleAttributeEntity> list = roleAttributeEntityRepository.findAll(ex);
    list
    .stream()
    .forEach(r -> {
        System.err.println(r.getRole());
        //assertTrue(list1.size() == 1);
    });
}


Regards. 
 

Комментарии:

1. Извините, что отличается от чего? Какие операторы SQL выполняются на самом деле?

2. Вы имеете в виду журнал поиска запроса? я снова проведу тест в понедельник (25). и поместите результат выполнения findAll(пример)..

3. Я понял, что происходит. атрибут ClientRole является «логическим собственным», и findAll (пример) не проверяет коллекции (по многим атрибутам), для меня это нормально (я понимаю сложность). странное поведение в результате, если «собственное логическое значение»..

4. Запрос с отображаемыми критериями -> выберите generatedAlias0 из RoleEntity как generatedAlias0, где generatedAlias0.clientRole=:param0 выберите roleentity0_. Идентификатор как id1_28_, roleentity0_. КЛИЕНТ как client2_28_, roleentity0_. CLIENT_REALM_CONSTRAINT как client_r3_28_, roleentity0_. CLIENT_ROLE как client_r4_28_, roleentity0_. ОПИСАНИЕ как descript5_28_, roleentity0_.NAME как name6_28_, roleentity0_.REALM как realm8_28_, roleentity0_.REALM_ID как realm_id7_28_ из KEYCLOAK_ROLE roleentity0_ где roleentity0_. CLIENT_ROLE=?

5. просто упомянем @Column(name="CLIENT_ROLE") private boolean clientRole; , что поскольку is native является «ложным» и Example.of (roleEntity) не проверяет lazyCollection (атрибуты) объекта RoleEntity