Отсутствует параметр IN или OUT в индексе :: 2 во время поиска объединенного объекта без столбца идентификатора - PullRequest
0 голосов
/ 26 апреля 2020

Это упрощенная версия того, что у меня есть, я сократил ее, чтобы сосредоточиться на проблеме. У меня есть большая таблица пользовательского интерфейса, основанная на StudentEntity, и я пытаюсь найти несколько разных столбцов (некоторые в StudentEntity и другие, основанные на совместных объектах)

Объект, который я хочу найти

public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", nullable = false)
    private Long id;

    @OneToOne(mappedBy = "student", fetch = FetchType.LAZY)
    private ReportEntity report;

    @ManyToOne
    @JoinColumn(name = "FAVOURITE_SUBJECT_ID")
    private SubjectEntity subject;
}

Сущность, доставляющая мне неприятности:


public class ReportEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", nullable = false)
    private Long id;

    @Column(name = "GRADE")
    private double grade;

    @Column(name = "REPORT_TITLE")
    private String title;

    @OneToOne
    @JoinColumn(name = "STUDENT_ID", nullable = false, unique = true)
    private StudentEntity student;
}

Сущность, которая отлично работает:

public class SubjectEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", nullable = false)
    private Long id;

    @Column(name = "NAME")
    private String name;
}

Настройка связанных параметров поиска в контроллере:

StudentSearchParameters params = new StudentSearchParameters();

if (favSubjects != null && !favSubjects.isEmpty()) {
    Iterable<SubjectEntity> subjects = subjectRepository.findAllByNameIn(favSubjects);
    params.setFavSubjects(subjects);
}
if (reportTitle != null) {
    Iterable<ReportEntity> reports = reportRepository.findAllByTitleLike(reportTitle);
    params.setReportTitles(reports);
}

Поиск с помощью Пользовательская спецификация ученика:

public Predicate toPredicate(Root<StudentEntity> root, CriteriaQuery<?> cq,
                                  CriteriaBuilder cb) {
    Predicate p = cb.and();

    ...

    // the keys and the value predicate in this map are used in the order by section, 
    // but that is working properly so I did not include it here
    Map<String, SearchRelation<?>> optionalEntities = new HashMap<>();
    optionalEntities.put(Constants.QUERY_PARAM_FAV_SUBJECTS, new
                SearchRelation<SubjectEntity>("subject", "name", params.getFavSubjects()));
    optionalEntities.put(Constants.QUERY_PARAM_REPORT_TITLE, new
                SearchRelation<ReportEntity>("report", "title", params.getReportTitles()));

    ...

    // -- Append optional join entities to predicate
    for (Map.Entry<String, SearchRelation<?>> me : optionalEntities.entrySet()) {

        if(me.getValue().getSearchList() == null) {
            continue;
        }

        SearchRelation relation = me.getValue();
        Predicate theseOptions = cb.or();

        for (Object entity : relation.getSearchList()) {
            // getSubjectReference is the prop name of the root entity eg 'subject' or 'report'
            theseOptions.getExpressions().add(cb.or(cb.equal(root.get(relation.getSubjectReference()), entity)));
        }

        p.getExpressions().add(cb.and(theseOptions));
    }

    return p;
}

Наконец, класс SearchRelation, который я использовал:

public class SearchRelation<T> {

    private String subjectReference;
    private String predicate;
    private Iterable<T> searchList;

    public SearchRelation(String subjectReference, String predicate, Iterable<T> searchList) {
        this.subjectReference = subjectReference;
        this.predicate = predicate;
        this.searchList = searchList;
    }

    public String getSubjectReference() {
        return subjectReference;
    }

    public String getPredicate() {
        return predicate;
    }

    public Iterable<T> getSearchList() {
        return searchList;
    }
}

Я (пытался) построить его таким образом, чтобы Spring мог обрабатывать объединения с помощью репозитории, и чтобы иметь возможность искать любой столбец объекта, который присоединен к root (Студент), просто добавив новый SearchRelation на карту в спецификации.

Как я уже сказал, я могу искать по теме, но при попытке сделать то же самое с отчетом я получаю ошибку:

Missing IN or OUT parameter at index:: 2

Я предполагаю, что это потому что в Student нет столбца с реальным идентификатором? Я бы предпочел не менять структуру БД. Есть ли способ, с помощью которого я могу использовать Criteria Builder и список сущностей из репозитория Spring для поиска объединенных сущностей без наличия столбца ID в root? Или я не в курсе, и есть какая-то другая проблема, которую я не получаю?

Обновление

Я установил P6Spy, чтобы увидеть, что на самом деле SQL выполняется против того, что регистрируется в спящем режиме. Hibernate дает мне (сжато) sql log:

select * from ( select col1, col2, ...... from "STUDENT" studen0_ where studen0_.ID=? ) where rownum <= ?


binding parameter [1] as [BIGINT] - [10960]

Я подтвердил, что в этом примере это правильный идентификатор. Однако, похоже, что он не привязан должным образом как журналы P6Spy:

select * from ( select col1, col2, ...... from "STUDENT" studen0_ where studen0_.ID=10 ) where rownum <= NULL

Я бы ожидал, что будет включено значение 10, так как это число строк, запрошенных из пользовательского интерфейса. Любая идея, почему он, кажется, не связывает параметр?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...